diff --git a/.clang-format b/.clang-format old mode 100644 new mode 100755 diff --git a/.dockerignore b/.dockerignore old mode 100644 new mode 100755 index 5d04d94ae3e08d52ffcf9cd54dcc67936cb486ad..31187b860fe0008583000cf51a7d4cf28b0cfa34 --- a/.dockerignore +++ b/.dockerignore @@ -5,4 +5,6 @@ build docs bin +scripts/foundry/sky130 +scripts/design/sky130_gcd **/target/ diff --git a/.gitee/ISSUE_TEMPLATE.en.md b/.gitee/ISSUE_TEMPLATE.en.md old mode 100644 new mode 100755 diff --git a/.gitee/ISSUE_TEMPLATE.zh-CN.md b/.gitee/ISSUE_TEMPLATE.zh-CN.md old mode 100644 new mode 100755 diff --git a/.gitee/PULL_REQUEST_TEMPLATE.en.md b/.gitee/PULL_REQUEST_TEMPLATE.en.md old mode 100644 new mode 100755 diff --git a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 20db44f408f87f21af683ee5935a8b2e4146249c..27fb474a9fc5544b3564cf1e84523319f3682066 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,4 @@ __pycache__ mcp_iEDA.egg-info/ # Prevent accidental re-addition of removed submodules -src/third_party/mt-kahypar/ \ No newline at end of file +src/third_party/mt-kahypar/ diff --git a/.gitmodules b/.gitmodules old mode 100644 new mode 100755 diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100644 new mode 100755 index ecc5c03b46270401c7e60880dd2ed0f50aebe888..809a6b125f4fc2680141df41b40b2b48b7bc44e0 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,8 +25,13 @@ set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -Werror=return-type") set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb -Werror=return-type") set(CMAKE_BUILD_TYPE "Release") -option(BUILD_STATIC_LIB "Build static library (default ON)" ON) -option(BUILD_PYTHON "Build Python bindings (default OFF)" OFF) +if(DEFINED BUILD_AIEDA) + option(BUILD_STATIC_LIB "Build static library OFF" OFF) + option(BUILD_PYTHON "Build Python bindings ON" ON) +else() + option(BUILD_STATIC_LIB "Build static library (default ON)" ON) + option(BUILD_PYTHON "Build Python bindings (default OFF)" OFF) +endif() option(USE_PROFILER "Enable performance profiling (default OFF)" OFF) option(SANITIZER "Enable address sanitizer (default OFF)" OFF) option(BUILD_GUI "Enable GUI components (default OFF)" OFF) @@ -109,8 +114,8 @@ add_subdirectory(src/utility) add_subdirectory(src/apps) add_subdirectory(src/database) add_subdirectory(src/interface) +add_subdirectory(src/vectorization) add_subdirectory(src/evaluation) -add_subdirectory(src/analysis) add_subdirectory(src/operation) add_subdirectory(src/platform) add_subdirectory(src/solver) diff --git a/CMakePresets.json b/CMakePresets.json deleted file mode 100644 index 12858bf2c704f81a9ba168ee35c51f46102cff06..0000000000000000000000000000000000000000 --- a/CMakePresets.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": 8, - "configurePresets": [ - { - "name": "Configure preset using toolchain file", - "displayName": "Configure preset using toolchain file", - "description": "Sets Ninja generator, build and install directory", - "generator": "Ninja", - "binaryDir": "${sourceDir}/out/build/${presetName}", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug", - "BUILD_PYTHON": "ON", - "BUILD_STATIC_LIB": "OFF", - "CMAKE_TOOLCHAIN_FILE": "", - "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}" - } - } - ] -} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README-CN.md b/README-CN.md old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/build.sh b/build.sh index 53b97bbdeefdddc8975522031537733d32bb3868..2763549e0c53d43cb6603655e9d9c0d7979688f9 100755 --- a/build.sh +++ b/build.sh @@ -182,7 +182,7 @@ install_dependencies_apt() g++-10 cmake ninja-build \ tcl-dev libgflags-dev libgoogle-glog-dev libboost-all-dev libgtest-dev flex\ libeigen3-dev libunwind-dev libmetis-dev libgmp-dev bison rustc cargo\ - libhwloc-dev libcairo2-dev libcurl4-openssl-dev + libhwloc-dev libcairo2-dev libcurl4-openssl-dev libtbb-dev git exit 0 else echo -e "${red}apt-get not found, pleas make sure you were running on Debian-Based Linux distribution${clear}" @@ -196,7 +196,10 @@ install_dependencies() sys_requirement_warning install_dependencies_apt elif [[ $INSTALL_DEP == "mirror" ]]; then - sed -i 's@//.*archive.ubuntu.com@//mirrors.tuna.tsinghua.edu.cn@g' /etc/apt/sources.list + sed -i \ + -e 's@//archive.ubuntu.com@//mirrors.tuna.tsinghua.edu.cn@g' \ + -e 's@//security.ubuntu.com@//mirrors.tuna.tsinghua.edu.cn@g' \ + /etc/apt/sources.list install_dependencies_apt elif [[ $INSTALL_DEP == "docker" ]]; then install_docker_experimental @@ -313,12 +316,17 @@ perform_clean() local cmake_build_dir="$BUILD_DIR" local rust_target_dirs=$(find "$IEDA_WORKSPACE/src" -type d -name "target" \ -exec test -f "{}/../Cargo.toml" \; -print 2>/dev/null) + local rust_tmp_dirs=$(find "$IEDA_WORKSPACE/src" -type d -name "tmp" \ + -exec test -f "{}/../Cargo.toml" \; -print 2>/dev/null) local delete_list=() [[ -d "$cmake_build_dir" ]] && delete_list+=("$cmake_build_dir (CMake build)") [[ -n "$rust_target_dirs" ]] && while IFS= read -r dir; do delete_list+=("$dir (Rust build)") done <<< "$rust_target_dirs" + [[ -n "$rust_tmp_dirs" ]] && while IFS= read -r dir; do + delete_list+=("$dir (Rust build)") + done <<< "$rust_tmp_dirs" if [[ ${#delete_list[@]} -eq 0 ]]; then echo -e "${green}No build artifacts found, nothing to clean.${clear}" @@ -333,6 +341,7 @@ perform_clean() if [[ $NON_INTERACTIVE == "ON" ]]; then [[ -d "$cmake_build_dir" ]] && rm -rf "$cmake_build_dir" [[ -n "$rust_target_dirs" ]] && xargs -I{} rm -rf {} <<< "$rust_target_dirs" + [[ -n "$rust_tmp_dirs" ]] && xargs -I{} rm -rf {} <<< "$rust_tmp_dirs" else read -p $'\nAre you sure to delete these? [y/N] ' confirm [[ $confirm == [yY] ]] || return 0 @@ -342,6 +351,9 @@ perform_clean() [[ -n "$rust_target_dirs" ]] && while IFS= read -r dir; do rm -rf "$dir" && echo "Deleted: $dir" done <<< "$rust_target_dirs" + [[ -n "$rust_tmp_dirs" ]] && while IFS= read -r dir; do + rm -rf "$dir" && echo "Deleted: $dir" + done <<< "$rust_tmp_dirs" fi echo -e "${green}Cleanup completed.${clear}" diff --git a/cmake/cuda.cmake b/cmake/cuda.cmake index 57148deb19a3fb4eb6b1488de2ff00cd5fed5d10..b9768a6adba0e9f4a10478c4c6d05714e1b19886 100644 --- a/cmake/cuda.cmake +++ b/cmake/cuda.cmake @@ -1,6 +1,6 @@ macro(ADD_CUDA_PROJ proj_name) - cmake_minimum_required(VERSION 3.24.0) +cmake_minimum_required(VERSION 3.24) cmake_policy(SET CMP0128 NEW) set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -17,7 +17,9 @@ set(CMAKE_CUDA_COMPILER /usr/local/cuda/bin/nvcc) set(CMAKE_CUDA_STANDARD 17) set(CMAKE_CUDA_STANDARD_REQUIRED ON) - enable_language(CUDA) +set(CMAKE_CUDA_COMPILER /usr/local/cuda-12.1/bin/nvcc) + +enable_language(CUDA) include(CheckLanguage) check_language(CUDA) diff --git a/cmake/operation/irt.cmake b/cmake/operation/irt.cmake index 9cfa2cad0d9302d6fc28dd9575c262f00dd03e79..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/cmake/operation/irt.cmake +++ b/cmake/operation/irt.cmake @@ -1 +0,0 @@ -message("irt build-------------------------") diff --git a/cmake/setting.cmake b/cmake/setting.cmake index f11d38312edf2b3a9a1f05870bfde3828007df4d..dfa312ef66561b588d9bcbe899b652217341e5e4 100644 --- a/cmake/setting.cmake +++ b/cmake/setting.cmake @@ -33,3 +33,6 @@ set(HOME_SOLVER ${PROJECT_SOURCE_DIR}/src/solver) #third party settings set(HOME_THIRDPARTY ${PROJECT_SOURCE_DIR}/src/third_party) + +#vectorization settings +set(HOME_VECTORIZATION ${PROJECT_SOURCE_DIR}/src/vectorization) diff --git a/docs/resources/idrc/EOL.png b/docs/resources/idrc/EOL.png new file mode 100644 index 0000000000000000000000000000000000000000..8072caf8c4a27fcf5cb853c4faf4c062f208e5a1 Binary files /dev/null and b/docs/resources/idrc/EOL.png differ diff --git a/docs/resources/idrc/classfig.png b/docs/resources/idrc/classfig.png new file mode 100644 index 0000000000000000000000000000000000000000..f77a764d8e7fc98d2875c31cf0067eac8c5d01a8 Binary files /dev/null and b/docs/resources/idrc/classfig.png differ diff --git a/docs/resources/idrc/classfig.vsdx b/docs/resources/idrc/classfig.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..ec08d3c61ddc9217d6a436be9d8fa07b20d43a31 Binary files /dev/null and b/docs/resources/idrc/classfig.vsdx differ diff --git a/docs/resources/idrc/classfig1.2.vsdx b/docs/resources/idrc/classfig1.2.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..14de5702fe09262ddac025a0a4ff2defcf560b43 Binary files /dev/null and b/docs/resources/idrc/classfig1.2.vsdx differ diff --git a/docs/resources/idrc/corner_fill.png b/docs/resources/idrc/corner_fill.png new file mode 100644 index 0000000000000000000000000000000000000000..237c972bcf1bfc73d15c58142627ba015882c8c0 Binary files /dev/null and b/docs/resources/idrc/corner_fill.png differ diff --git a/docs/resources/idrc/cut_spacing.png b/docs/resources/idrc/cut_spacing.png new file mode 100644 index 0000000000000000000000000000000000000000..7be71a0c4982e5baa73f18ccdf002041a87aa381 Binary files /dev/null and b/docs/resources/idrc/cut_spacing.png differ diff --git a/docs/resources/idrc/enclosure.png b/docs/resources/idrc/enclosure.png new file mode 100644 index 0000000000000000000000000000000000000000..1a41a9080649b74c2461f3318d83bff84674c138 Binary files /dev/null and b/docs/resources/idrc/enclosure.png differ diff --git a/docs/resources/idrc/fig1.1.png b/docs/resources/idrc/fig1.1.png new file mode 100644 index 0000000000000000000000000000000000000000..e2ffe56159eda6c92d736791380b40945cdfdcb4 Binary files /dev/null and b/docs/resources/idrc/fig1.1.png differ diff --git a/docs/resources/idrc/fig1.2.png b/docs/resources/idrc/fig1.2.png new file mode 100644 index 0000000000000000000000000000000000000000..cfb8232d1e2497bac605736efed4b94cd4622861 Binary files /dev/null and b/docs/resources/idrc/fig1.2.png differ diff --git a/docs/resources/idrc/fig1.3.png b/docs/resources/idrc/fig1.3.png new file mode 100644 index 0000000000000000000000000000000000000000..04d638264e461096bd7ae48b9645ef3e954b98d9 Binary files /dev/null and b/docs/resources/idrc/fig1.3.png differ diff --git a/docs/resources/idrc/fig1.4.png b/docs/resources/idrc/fig1.4.png new file mode 100644 index 0000000000000000000000000000000000000000..a7ca7bb3df4941f94b7899f3228a2d9fafcc28a2 Binary files /dev/null and b/docs/resources/idrc/fig1.4.png differ diff --git a/docs/resources/idrc/fig1.5.png b/docs/resources/idrc/fig1.5.png new file mode 100644 index 0000000000000000000000000000000000000000..70e243c8972e1c934b62832044d0641f0ac6827c Binary files /dev/null and b/docs/resources/idrc/fig1.5.png differ diff --git a/docs/resources/idrc/fig1.6.png b/docs/resources/idrc/fig1.6.png new file mode 100644 index 0000000000000000000000000000000000000000..0a7ba8b02121282262b19713d798d44f10540134 Binary files /dev/null and b/docs/resources/idrc/fig1.6.png differ diff --git a/docs/resources/idrc/fig2.1.png b/docs/resources/idrc/fig2.1.png new file mode 100644 index 0000000000000000000000000000000000000000..171cbe40b201b75f58cee8c3aef413a3aba6de09 Binary files /dev/null and b/docs/resources/idrc/fig2.1.png differ diff --git a/docs/resources/idrc/fig2.11.png b/docs/resources/idrc/fig2.11.png new file mode 100644 index 0000000000000000000000000000000000000000..0663e9e862beff506bf625da490611800f43f9bc Binary files /dev/null and b/docs/resources/idrc/fig2.11.png differ diff --git a/docs/resources/idrc/fig2.2.png b/docs/resources/idrc/fig2.2.png new file mode 100644 index 0000000000000000000000000000000000000000..4a3a44c5a3173a758f3add0fb75b1ce30387d28f Binary files /dev/null and b/docs/resources/idrc/fig2.2.png differ diff --git a/docs/resources/idrc/fig2.3.png b/docs/resources/idrc/fig2.3.png new file mode 100644 index 0000000000000000000000000000000000000000..69e0c8f1ea8f1544d17a3a4a1c64e578931c2f2a Binary files /dev/null and b/docs/resources/idrc/fig2.3.png differ diff --git a/docs/resources/idrc/fig2.7.png b/docs/resources/idrc/fig2.7.png new file mode 100644 index 0000000000000000000000000000000000000000..fab634e87093f43ecdd46c97e5dab77470480fd1 Binary files /dev/null and b/docs/resources/idrc/fig2.7.png differ diff --git a/docs/resources/idrc/fig2.8.png b/docs/resources/idrc/fig2.8.png new file mode 100644 index 0000000000000000000000000000000000000000..806ff9616af970bd647d54deb967ee0025218ba4 Binary files /dev/null and b/docs/resources/idrc/fig2.8.png differ diff --git a/docs/resources/idrc/jog.png b/docs/resources/idrc/jog.png new file mode 100644 index 0000000000000000000000000000000000000000..cc052e9060c1d6d5458f2ebd6deb168dbc9947e5 Binary files /dev/null and b/docs/resources/idrc/jog.png differ diff --git a/docs/resources/idrc/minstep.png b/docs/resources/idrc/minstep.png new file mode 100644 index 0000000000000000000000000000000000000000..8a23e36dd6d4ea5d71f0cbe54ad1015ae0e4353d Binary files /dev/null and b/docs/resources/idrc/minstep.png differ diff --git a/docs/resources/idrc/notch.png b/docs/resources/idrc/notch.png new file mode 100644 index 0000000000000000000000000000000000000000..4ab00336e989af041924647b2063e82b129b74cb Binary files /dev/null and b/docs/resources/idrc/notch.png differ diff --git a/docs/resources/idrc/path.png b/docs/resources/idrc/path.png new file mode 100644 index 0000000000000000000000000000000000000000..d7cbae6ee0438b79144a924e7de904200fc360a1 Binary files /dev/null and b/docs/resources/idrc/path.png differ diff --git a/docs/resources/idrc/plot1.png b/docs/resources/idrc/plot1.png new file mode 100644 index 0000000000000000000000000000000000000000..59607270a5a8c419359083f2107a0cb686ec3a09 Binary files /dev/null and b/docs/resources/idrc/plot1.png differ diff --git a/docs/resources/idrc/plot1.vsdx b/docs/resources/idrc/plot1.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..cb446b45050263a6677bb444bc13ce6c04d97345 Binary files /dev/null and b/docs/resources/idrc/plot1.vsdx differ diff --git a/docs/resources/idrc/plot2.10.png b/docs/resources/idrc/plot2.10.png new file mode 100644 index 0000000000000000000000000000000000000000..615adfb03e047f36982e90fc88b487e467ff2620 Binary files /dev/null and b/docs/resources/idrc/plot2.10.png differ diff --git a/docs/resources/idrc/plot2.10.vsdx b/docs/resources/idrc/plot2.10.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..21f15ded42e66ee3b040107d0e5efb2588d53710 Binary files /dev/null and b/docs/resources/idrc/plot2.10.vsdx differ diff --git a/docs/resources/idrc/plot2.4.png b/docs/resources/idrc/plot2.4.png new file mode 100644 index 0000000000000000000000000000000000000000..feb71e9d07b7c56fd59155fe2727800e66f9ace6 Binary files /dev/null and b/docs/resources/idrc/plot2.4.png differ diff --git a/docs/resources/idrc/plot2.4.vsdx b/docs/resources/idrc/plot2.4.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..4caa148db6e9cfdded9dedc7e4220bcb59e1b74b Binary files /dev/null and b/docs/resources/idrc/plot2.4.vsdx differ diff --git a/docs/resources/idrc/plot2.5.png b/docs/resources/idrc/plot2.5.png new file mode 100644 index 0000000000000000000000000000000000000000..82da20e2c6130bad18512fdf6474e32d40c25f4e Binary files /dev/null and b/docs/resources/idrc/plot2.5.png differ diff --git a/docs/resources/idrc/plot2.5.vsdx b/docs/resources/idrc/plot2.5.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..fbc9df56074a82781ede7de64ddf1a8a63dca761 Binary files /dev/null and b/docs/resources/idrc/plot2.5.vsdx differ diff --git a/docs/resources/idrc/plot2.6.png b/docs/resources/idrc/plot2.6.png new file mode 100644 index 0000000000000000000000000000000000000000..c9ad8b6ccb6b88a79f2d03306efbf820a18328ee Binary files /dev/null and b/docs/resources/idrc/plot2.6.png differ diff --git a/docs/resources/idrc/plot2.6.vsdx b/docs/resources/idrc/plot2.6.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..bac18efa61527140391b191cf4374d5c7d1c3005 Binary files /dev/null and b/docs/resources/idrc/plot2.6.vsdx differ diff --git a/docs/resources/idrc/plot2.9.png b/docs/resources/idrc/plot2.9.png new file mode 100644 index 0000000000000000000000000000000000000000..36d50191b2202417f1ca523d1df81fdeffa6cdae Binary files /dev/null and b/docs/resources/idrc/plot2.9.png differ diff --git a/docs/resources/idrc/plot2.9.vsdx b/docs/resources/idrc/plot2.9.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..7ad6e2daa7aa9d7c9a97d802d4ccbf077ec0ba00 Binary files /dev/null and b/docs/resources/idrc/plot2.9.vsdx differ diff --git a/docs/resources/idrc/plot2.png b/docs/resources/idrc/plot2.png new file mode 100644 index 0000000000000000000000000000000000000000..1d70f65b364769d59b908dbba3c12f79d263928d Binary files /dev/null and b/docs/resources/idrc/plot2.png differ diff --git a/docs/resources/idrc/plot2.vsdx b/docs/resources/idrc/plot2.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..a892e748a925bdd320a88deb937509b0c90b1e28 Binary files /dev/null and b/docs/resources/idrc/plot2.vsdx differ diff --git a/docs/resources/idrc/softeframe.png b/docs/resources/idrc/softeframe.png new file mode 100644 index 0000000000000000000000000000000000000000..e7c1c5aec04c00e625efc701aa35d475ee1099e1 Binary files /dev/null and b/docs/resources/idrc/softeframe.png differ diff --git a/scripts/.gitignore b/scripts/.gitignore index 91f878462f2e2b43478b2893f7275cd8b1aeafbb..0e4f7f49f7d05b1ad8e22762fbdd484e969ddd12 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -1,8 +1,3 @@ -28nm -110nm -design/smic180 -design/sky130_gcd_0.6 -design/sky130_gcd_0.8 __pycache__/ *.py[cod] *$py.class \ No newline at end of file diff --git a/scripts/design/ihp130_gcd/iEDA_config/flow_config.json b/scripts/design/ihp130_gcd/iEDA_config/flow_config.json index 959a181fa03f292b8980657501cd630f27ea32aa..ff00cd0bc4b8d3f463c0e27f814f9a4c87b8d290 100644 --- a/scripts/design/ihp130_gcd/iEDA_config/flow_config.json +++ b/scripts/design/ihp130_gcd/iEDA_config/flow_config.json @@ -1,24 +1,12 @@ { - "Tools": { - "TCL": "ON" - }, - "Flow": { - "Synthesis": "OFF", - "Floorplan": "OFF", - "Placer": "OFF", - "CTS": "OFF", - "TO": "OFF", - "Router": "OFF", - "DRC": "OFF", - "GUI": "OFF" - }, "ConfigPath": { - "idb_path": "$IEDA_CONFIG_DIR/db_default_config.json", - "ifp_path": "$IEDA_CONFIG_DIR/fp_default_config.json", - "ipl_path": "$IEDA_CONFIG_DIR/pl_default_config.json", - "irt_path": "$IEDA_CONFIG_DIR/rt_default_config.json", - "idrc_path": "$IEDA_CONFIG_DIR/drc_default_config.json", - "icts_path": "$IEDA_CONFIG_DIR/cts_default_config.json", - "ito_path": "ERROR_OPTION_DEPRECATED" + "idb_path": "$CONFIG_DIR/db_default_config.json", + "ifp_path": "$CONFIG_DIR/fp_default_config.json", + "ipl_path": "$CONFIG_DIR/pl_default_config.json", + "irt_path": "$CONFIG_DIR/rt_default_config.json", + "idrc_path": "$CONFIG_DIR/drc_default_config.json", + "icts_path": "$CONFIG_DIR/cts_default_config.json", + "ito_path": "$CONFIG_DIR/to_default_config.json", + "ipnp_path": "$CONFIG_DIR/pnp_default_config.json" } } \ No newline at end of file diff --git a/scripts/design/ihp130_gcd/iEDA_config/pnp_default_config.json b/scripts/design/ihp130_gcd/iEDA_config/pnp_default_config.json new file mode 100644 index 0000000000000000000000000000000000000000..c93aea3fa0feda4c5b2945dac12aae9473c6c228 --- /dev/null +++ b/scripts/design/ihp130_gcd/iEDA_config/pnp_default_config.json @@ -0,0 +1,76 @@ +{ + "timing": { + "design_workspace": "" + }, + "power": { + "power_net_name": "VDD" + }, + "egr": { + "map_path": "" + }, + "grid": { + "power_layers": [ + 9, + 8, + 7, + 6, + 5, + 4, + 3 + ], + "ho_region_num": 2, + "ver_region_num": 2 + }, + "simulated_annealing": { + "initial_temp": 100.0, + "cooling_rate": 0.95, + "min_temp": 0.1, + "iterations_per_temp": 10, + "ir_drop_weight": 0.6, + "overflow_weight": 0.4, + "modifiable_layer_min": 3, + "modifiable_layer_max": 6 + }, + "templates": { + "horizontal": [ + { + "width": 8000.0, + "pg_offset": 1600.0, + "space": 19200.0, + "offset": 8000.0 + }, + { + "width": 8000.0, + "pg_offset": 1600.0, + "space": 38400.0, + "offset": 8000.0 + }, + { + "width": 8000.0, + "pg_offset": 1600.0, + "space": 38400.0, + "offset": 27200.0 + } + ], + "vertical": [ + { + "width": 8000.0, + "pg_offset": 1600.0, + "space": 19200.0, + "offset": 8000.0 + }, + { + "width": 8000.0, + "pg_offset": 1600.0, + "space": 38400.0, + "offset": 8000.0 + }, + { + "width": 8000.0, + "pg_offset": 1600.0, + "space": 38400.0, + "offset": 27200.0 + } + ] + } +} \ No newline at end of file diff --git a/scripts/design/ihp130_gcd/script/iFP_script/run_iFP.tcl b/scripts/design/ihp130_gcd/script/iFP_script/run_iFP.tcl index 5314e23f2f0908811489f19bca067bfe702e4be2..fb24d86dbdbe2dace7934284c77c2d881290da4c 100755 --- a/scripts/design/ihp130_gcd/script/iFP_script/run_iFP.tcl +++ b/scripts/design/ihp130_gcd/script/iFP_script/run_iFP.tcl @@ -9,8 +9,15 @@ set NETLIST_FILE "$::env(NETLIST_FILE)" # input variables set TOP_NAME "$::env(TOP_NAME)" -set DIE_AREA "$::env(DIE_AREA)" -set CORE_AREA "$::env(CORE_AREA)" +set USE_FIXED_BBOX "$::env(USE_FIXED_BBOX)" +puts ">>> iFP: USE_FIXED_BBOX $USE_FIXED_BBOX" +if { $USE_FIXED_BBOX == "False" } { + set CORE_UTIL "$::env(CORE_UTIL)" +} else { + set DIE_BBOX "$::env(DIE_BBOX)" + set CORE_BBOX "$::env(CORE_BBOX)" +} + # output files set OUTPUT_DEF "$RESULT_DIR/iFP_result.def" @@ -63,12 +70,23 @@ set PLACE_SITE CoreSite set IO_SITE sg13g2_ioSite set CORNER_SITE sg13g2_ioSite -init_floorplan \ - -die_area $DIE_AREA \ - -core_area $CORE_AREA \ - -core_site $PLACE_SITE \ - -io_site $IO_SITE \ - -corner_site $CORNER_SITE +if { $USE_FIXED_BBOX == "False" } { + puts ">>> iFP: using core_util $CORE_UTIL" + init_floorplan \ + -core_util $CORE_UTIL \ + -core_site $PLACE_SITE \ + -io_site $IO_SITE \ + -corner_site $CORNER_SITE +} else { + puts ">>> iFP: using fixed area die $DIE_BBOX, and core $CORE_BBOX" + init_floorplan \ + -die_area $DIE_BBOX \ + -core_area $CORE_BBOX \ + -core_site $PLACE_SITE \ + -io_site $IO_SITE \ + -corner_site $CORNER_SITE +} + source $IEDA_TCL_SCRIPT_DIR/iFP_script/module/create_tracks.tcl diff --git a/scripts/design/ihp130_gcd/script/iRT_script/run_iRT.tcl b/scripts/design/ihp130_gcd/script/iRT_script/run_iRT.tcl index 77b3e9e0eed8ebb1988d7666350e41f197b705bc..cd224d9051394054b0d106d22b30baa5c669fa02 100755 --- a/scripts/design/ihp130_gcd/script/iRT_script/run_iRT.tcl +++ b/scripts/design/ihp130_gcd/script/iRT_script/run_iRT.tcl @@ -62,21 +62,24 @@ def_init -path $INPUT_DEF #=========================================================== ## run Router #=========================================================== +init_notification + init_rt -temp_directory_path $TOOL_REPORT_DIR \ -bottom_routing_layer "Metal2" \ -top_routing_layer "Metal5" \ -thread_number $NUM_THREADS \ -output_inter_result 0 \ + -enable_notification 0 \ -enable_timing 0 \ -enable_fast_mode 0 run_rt +destroy_rt + # report_timing -stage "dr" feature_tool -path $TOOL_METRICS_JSON -step route -destroy_rt - #=========================================================== ## save def & netlist #=========================================================== diff --git a/scripts/design/sky130_gcd/iEDA_config/flow_config.json b/scripts/design/sky130_gcd/iEDA_config/flow_config.json index c5aaf99e33f593ba71528187715d194b00ed163c..ff00cd0bc4b8d3f463c0e27f814f9a4c87b8d290 100644 --- a/scripts/design/sky130_gcd/iEDA_config/flow_config.json +++ b/scripts/design/sky130_gcd/iEDA_config/flow_config.json @@ -1,17 +1,4 @@ { - "Tools": { - "TCL": "ON" - }, - "Flow": { - "Synthesis": "ON", - "Floorplan": "ON", - "Placer": "ON", - "CTS": "ON", - "TO": "ON", - "Router": "ON", - "DRC": "ON", - "GUI": "ON" - }, "ConfigPath": { "idb_path": "$CONFIG_DIR/db_default_config.json", "ifp_path": "$CONFIG_DIR/fp_default_config.json", @@ -19,6 +6,7 @@ "irt_path": "$CONFIG_DIR/rt_default_config.json", "idrc_path": "$CONFIG_DIR/drc_default_config.json", "icts_path": "$CONFIG_DIR/cts_default_config.json", - "ito_path": "$CONFIG_DIR/to_default_config.json" + "ito_path": "$CONFIG_DIR/to_default_config.json", + "ipnp_path": "$CONFIG_DIR/pnp_default_config.json" } } \ No newline at end of file diff --git a/scripts/design/sky130_gcd/iEDA_config/pnp_default_config.json b/scripts/design/sky130_gcd/iEDA_config/pnp_default_config.json new file mode 100644 index 0000000000000000000000000000000000000000..c9a31a636f49ce5f2a3f906ae1a45cac79b6953f --- /dev/null +++ b/scripts/design/sky130_gcd/iEDA_config/pnp_default_config.json @@ -0,0 +1,55 @@ +{ + "timing": { + "design_workspace": "" + }, + "power": { + "power_net_name": "VDD" + }, + "egr": { + "map_path": "" + }, + "grid": { + "power_layers": [ + "met5", + "met4" + ], + "follow_pin_layers": [ + "met1" + ], + "follow_pin_width": 480.0, + "power_port_layer": "met5", + "ho_region_num": 1, + "ver_region_num": 1 + }, + "simulated_annealing": { + "initial_temp": 100.0, + "cooling_rate": 0.95, + "min_temp": 0.1, + "iterations_per_temp": 10, + "ir_drop_weight": 0.6, + "overflow_weight": 0.4, + "modifiable_layer_min": "met2", + "modifiable_layer_max": "met5" + }, + "templates": { + "horizontal": [ + { + "width": 1600.0, + "pg_offset": 6800.0, + "space": 13600.0, + "offset": 1200.0 + } + ], + "vertical": [ + { + "width": 1600.0, + "pg_offset": 6800.0, + "space": 13600.0, + "offset": 1200.0 + } + ], + "layer_specific": { + + } + } +} \ No newline at end of file diff --git a/scripts/design/sky130_gcd/script/iFP_script/module/pdn.tcl b/scripts/design/sky130_gcd/script/iFP_script/module/pdn.tcl index f130d095e4fb556492b4091f799d807d32b80055..46296223b6145cbb9bfdf6af7f55daeb839ea463 100755 --- a/scripts/design/sky130_gcd/script/iFP_script/module/pdn.tcl +++ b/scripts/design/sky130_gcd/script/iFP_script/module/pdn.tcl @@ -1,5 +1,5 @@ -add_pdn_io -net_name VDD -direction INOUT -is_power 1 -add_pdn_io -net_name VSS -direction INOUT -is_power 0 +# add_pdn_io -net_name VDD -direction INOUT -is_power 1 +# add_pdn_io -net_name VSS -direction INOUT -is_power 0 global_net_connect -net_name VDD -instance_pin_name VPWR -is_power 1 global_net_connect -net_name VDD -instance_pin_name VPB -is_power 1 diff --git a/scripts/design/sky130_gcd/script/iFP_script/run_iFP.tcl b/scripts/design/sky130_gcd/script/iFP_script/run_iFP.tcl index 4059d8047c56a3b7c0cd78292b329fa3557c5b3c..e0dec515b9cf5072a9db6bda1cf4e25e1b97a6f9 100755 --- a/scripts/design/sky130_gcd/script/iFP_script/run_iFP.tcl +++ b/scripts/design/sky130_gcd/script/iFP_script/run_iFP.tcl @@ -61,7 +61,13 @@ init_floorplan \ source $::env(TCL_SCRIPT_DIR)/iFP_script/module/create_tracks.tcl #=========================================================== -## Place IO Port +## add io port for pdn +#=========================================================== +add_pdn_io -net_name VDD -direction INOUT -is_power 1 +add_pdn_io -net_name VSS -direction INOUT -is_power 0 +#=========================================================== +## Place IO Port +## -sides "left right top bottom" #=========================================================== auto_place_pins -layer met5 -width 2000 -height 2000 @@ -76,7 +82,7 @@ tapcell \ #=========================================================== ## PDN #=========================================================== -#source $::env(TCL_SCRIPT_DIR)/iFP_script/module/pdn.tcl +source $::env(TCL_SCRIPT_DIR)/iFP_script/module/pdn.tcl #=========================================================== ## set clock net diff --git a/scripts/design/sky130_gcd/script/iPNP/run_iPNP.tcl b/scripts/design/sky130_gcd/script/iPNP/run_iPNP.tcl index af5f48ea5aa8b613504136eeb09c1799e3e1b7fe..897d1156400d090ca930b3c07d4e407267f2be75 100755 --- a/scripts/design/sky130_gcd/script/iPNP/run_iPNP.tcl +++ b/scripts/design/sky130_gcd/script/iPNP/run_iPNP.tcl @@ -6,13 +6,23 @@ flow_init -config $::env(CONFIG_DIR)/flow_config.json #=========================================================== ## read db config #=========================================================== -db_init -config $::env(CONFIG_DIR)/db_default_config.json +db_init -config $::env(CONFIG_DIR)/db_default_config.json -output_dir_path $::env(RESULT_DIR) #=========================================================== ## reset data path #=========================================================== source $::env(TCL_SCRIPT_DIR)/DB_script/db_path_setting.tcl +#=========================================================== +## reset lib +#=========================================================== +source $::env(TCL_SCRIPT_DIR)/DB_script/db_init_lib.tcl + +#=========================================================== +## reset sdc +#=========================================================== +source $::env(TCL_SCRIPT_DIR)/DB_script/db_init_sdc.tcl + #=========================================================== ## read lef #=========================================================== @@ -21,17 +31,19 @@ source $::env(TCL_SCRIPT_DIR)/DB_script/db_init_lef.tcl #=========================================================== ## read def #=========================================================== -def_init -path $::env(RESULT_DIR)/iFP_result.def +set DEFAULT_INPUT_DEF "$::env(RESULT_DIR)/iFP_result.def" +def_init -path [expr {[info exists ::env(INPUT_DEF)]? $::env(INPUT_DEF) : $DEFAULT_INPUT_DEF}] #=========================================================== ## run PNP #=========================================================== -run_pnp +run_pnp -config $::env(CONFIG_DIR)/pnp_default_config.json #=========================================================== ## def & netlist #=========================================================== -def_save -path $::env(RESULT_DIR)/iPNP_result.def +set DEFAULT_OUTPUT_DEF "$::env(RESULT_DIR)/iPNP_result.def" +def_save -path [expr {[info exists ::env(OUTPUT_DEF)] ? $::env(OUTPUT_DEF) : $DEFAULT_OUTPUT_DEF}] #=========================================================== ## save netlist diff --git a/src/analysis/CMakeLists.txt b/src/analysis/CMakeLists.txt deleted file mode 100644 index 55d6276e9c15d6b77c75a6394440071a68bccc2e..0000000000000000000000000000000000000000 --- a/src/analysis/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_subdirectory(data) -add_subdirectory(config) -add_subdirectory(api) -add_subdirectory(module) diff --git a/src/analysis/data/CMakeLists.txt b/src/analysis/data/CMakeLists.txt deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/analysis/module/CMakeLists.txt b/src/analysis/module/CMakeLists.txt deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/apps/ieda_main.cpp b/src/apps/ieda_main.cpp index a1abdb895f14bd16c9105db234d695aea300cf0a..eb62ebf2b58a6aed6442b4ae7e251bbeddaa7c51 100644 --- a/src/apps/ieda_main.cpp +++ b/src/apps/ieda_main.cpp @@ -27,11 +27,15 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "../platform/flow/flow.h" +#include "log/Log.hh" +#include "time/Time.hh" using namespace iplf; int main(int argc, char** argv) { + ieda::Time::start(); + if (argc == 1) { argv[0] = const_cast("UserShell\n"); } @@ -41,6 +45,12 @@ int main(int argc, char** argv) if (std::string("-v") == argv[i]) { printVersion = true; } + + // support specific log directory + if (std::string("-log") == argv[i]) { + ieda::Log::init(argv, argv[i + 1]); + } + if (std::string("-script") == argv[i]) { // discard every args before the (first) "-script" // pass the rest of the args to Tcl interpreter diff --git a/src/database/data/design/CMakeLists.txt b/src/database/data/design/CMakeLists.txt index 9bd77874079445f3dd6b7914ac4dede011b8c3cd..15ab6c134c6a3c1eb6246b8dc03ac1feb88cd2ed 100644 --- a/src/database/data/design/CMakeLists.txt +++ b/src/database/data/design/CMakeLists.txt @@ -15,4 +15,4 @@ target_include_directories(idb ${HOME_UTILITY}/string ) -target_link_libraries(idb PRIVATE str geometry_db) +target_link_libraries(idb PRIVATE str geometry_db) \ No newline at end of file diff --git a/src/database/data/design/db_design/IdbNet.cpp b/src/database/data/design/db_design/IdbNet.cpp index 966b4098271ec6e456456f9010da4f0e0e5f1ca7..4d087bf8297cebf1bc9180ff3f28ab67e4ea4374 100644 --- a/src/database/data/design/db_design/IdbNet.cpp +++ b/src/database/data/design/db_design/IdbNet.cpp @@ -108,6 +108,15 @@ void IdbNet::set_source_type(string type) // IdbPin* IdbNet::findDrivingPin() IdbPin* IdbNet::get_driving_pin() { + /// 1st step : check if exist instance output pin, if existed, it is driving pin + for (IdbPin* pin : _instance_pin_list->get_pin_list()) { + if (pin->get_term()->get_direction() == IdbConnectDirection::kOutput + || pin->get_term()->get_direction() == IdbConnectDirection::kOutputTriState) { + return pin; + } + } + + /// 2nd step : if instance output pin not exist, find io pin with input direction for (IdbPin* io_pin : _io_pin_list->get_pin_list()) { // case 2 if (io_pin->get_term()->get_direction() == IdbConnectDirection::kInput) { @@ -115,12 +124,13 @@ IdbPin* IdbNet::get_driving_pin() } } - for (IdbPin* pin : _instance_pin_list->get_pin_list()) { - if (pin->get_term()->get_direction() == IdbConnectDirection::kOutput) { - return pin; + /// 3nd step, if io input pin not exist, find io pin with inout direction + for (IdbPin* io_pin : _io_pin_list->get_pin_list()) { + // case 2 + if (io_pin->get_term()->get_direction() == IdbConnectDirection::kInOut) { + return io_pin; } } - // // case 3 or case 4 // IdbInstance* instance = instance_pin->get_instance(); // IdbPins* instance_pin_list = instance->get_pin_list(); @@ -130,7 +140,7 @@ IdbPin* IdbNet::get_driving_pin() // } // } - // std::cout << "Error : No driven pin exist..." << std::endl; + std::cout << "Error : No driver pin exist..." << std::endl; return nullptr; } @@ -138,22 +148,38 @@ vector IdbNet::get_load_pins() { vector pin_list; - for (IdbPin* io_pin : _io_pin_list->get_pin_list()) { - // case 2 - if (io_pin->get_term()->get_direction() == IdbConnectDirection::kOutput) { - pin_list.emplace_back(io_pin); - } - } + auto* driver_pin = get_driving_pin(); - for (IdbPin* pin : _instance_pin_list->get_pin_list()) { - if (pin->get_term()->get_direction() == IdbConnectDirection::kInput) { - pin_list.emplace_back(pin); - } - } + std::copy(_io_pin_list->get_pin_list().begin(), _io_pin_list->get_pin_list().end(), std::back_inserter(pin_list)); + std::copy(_instance_pin_list->get_pin_list().begin(), _instance_pin_list->get_pin_list().end(), std::back_inserter(pin_list)); + + pin_list.erase(std::remove(pin_list.begin(), pin_list.end(), driver_pin), pin_list.end()); return pin_list; } +IdbRect* IdbNet::get_bounding_box() +{ + int32_t min_lx = INT32_MAX; + int32_t min_ly = INT32_MAX; + int32_t max_ux = INT32_MIN; + int32_t max_uy = INT32_MIN; + auto* idb_driving_pin = get_driving_pin(); + if (idb_driving_pin != nullptr) { + min_lx = idb_driving_pin->get_average_coordinate()->get_x(); + min_ly = idb_driving_pin->get_average_coordinate()->get_y(); + max_ux = idb_driving_pin->get_average_coordinate()->get_x(); + max_uy = idb_driving_pin->get_average_coordinate()->get_y(); + } + for (auto* idb_load_pin : get_load_pins()) { + min_lx = std::min(min_lx, idb_load_pin->get_average_coordinate()->get_x()); + min_ly = std::min(min_ly, idb_load_pin->get_average_coordinate()->get_y()); + max_ux = std::max(max_ux, idb_load_pin->get_average_coordinate()->get_x()); + max_uy = std::max(max_uy, idb_load_pin->get_average_coordinate()->get_y()); + } + return new IdbRect(min_lx, min_ly, max_ux, max_uy); +} + bool IdbNet::set_bounding_box() { // IdbRect* rect = get_bounding_box(); diff --git a/src/database/data/design/db_design/IdbNet.h b/src/database/data/design/db_design/IdbNet.h index 3b94ea72cecbe2180ab7d43337e12c4708cc29f8..8e819e9906a9508750db6d6984aa61f8c6db00dd 100644 --- a/src/database/data/design/db_design/IdbNet.h +++ b/src/database/data/design/db_design/IdbNet.h @@ -150,6 +150,7 @@ class IdbNet : public IdbObject IdbPin* get_driving_pin(); + IdbRect* get_bounding_box(); // setter void set_net_name(string name) { diff --git a/src/database/data/design/db_design/IdbVias.cpp b/src/database/data/design/db_design/IdbVias.cpp index 4358593da9f5118a6920760f3a3b044a4075ca29..2ecbc0a82c8744fe50b0a44a18ac2d7a63c4df7c 100644 --- a/src/database/data/design/db_design/IdbVias.cpp +++ b/src/database/data/design/db_design/IdbVias.cpp @@ -34,6 +34,7 @@ #include #include +#include #include "../db_layout/IdbLayer.h" #include "IdbViaMaster.h" @@ -334,6 +335,12 @@ IdbVia* IdbVias::createVia(string via_name, IdbLayerCut* layer_cut, int32_t widt int32_t spacing_x = via_rule->get_spacing_x(); int32_t spacing_y = via_rule->get_spacing_y(); + if (!layer_cut->get_spacings().empty()) { + int layer_cut_spacing = layer_cut->get_spacings().at(0)->get_spacing(); + spacing_x = std::max(spacing_x, cutsize_x + layer_cut_spacing); + spacing_y = std::max(spacing_y, cutsize_y + layer_cut_spacing); + } + int32_t cut_spacing_x = spacing_x - cutsize_x; int32_t cut_spacing_y = spacing_y - cutsize_y; master_generate->set_cut_spacing(cut_spacing_x, cut_spacing_y); @@ -687,6 +694,12 @@ std::pair IdbVias::calculateRowsCols(IdbLayerCut* layer_cut, i int32_t spacing_x = via_rule->get_spacing_x(); int32_t spacing_y = via_rule->get_spacing_y(); + if (!layer_cut->get_spacings().empty()) { + int layer_cut_spacing = layer_cut->get_spacings().at(0)->get_spacing(); + spacing_x = std::max(spacing_x, cutsize_x + layer_cut_spacing); + spacing_y = std::max(spacing_y, cutsize_y + layer_cut_spacing); + } + if (width > 0 && height > 0) { num_rows = std::max(kMinRowColNum + (height - cutsize_y) / spacing_y, kMinRowColNum); num_cols = std::max(kMinRowColNum + (width - cutsize_x) / spacing_x, kMinRowColNum); diff --git a/src/database/manager/builder/def_builder/CMakeLists.txt b/src/database/manager/builder/def_builder/CMakeLists.txt index 5a4cfe1c2f2f04fff266c00e5787a3b902c1c2d1..67322a711da66ecfd78e5284066ec12a6dacfa93 100644 --- a/src/database/manager/builder/def_builder/CMakeLists.txt +++ b/src/database/manager/builder/def_builder/CMakeLists.txt @@ -21,4 +21,4 @@ target_include_directories(def_builder ${HOME_THIRDPARTY}/lefdef/def/defzlib ) -target_link_libraries(def_builder PRIVATE def defzlib str solver_geometry_boost) \ No newline at end of file +target_link_libraries(def_builder PRIVATE def defzlib str solver_geometry_boost) diff --git a/src/database/manager/builder/def_builder/def_read.cpp b/src/database/manager/builder/def_builder/def_read.cpp index 4680309fb1bc0e3b6d3ccb7c9b0a54a88a57f133..39af9368d3fc44d704bf42bc211be0601f269633 100644 --- a/src/database/manager/builder/def_builder/def_read.cpp +++ b/src/database/manager/builder/def_builder/def_read.cpp @@ -904,6 +904,10 @@ int32_t DefRead::parse_component(defiComponent* def_component) std::string inst_name = def_component->id(); std::string new_inst_name = ieda::Str::trimEscape(inst_name); + if ("u_NV_NVDLA_cbuf/u_cbuf_ram_bank6_ram0/rmod/u_mema" == new_inst_name) { + int a = 0; + a += 1; + } IdbInstance* instance = instance_list->add_instance(new_inst_name); if (instance == nullptr) { diff --git a/src/database/manager/builder/verilog_builder/verilog_read.cpp b/src/database/manager/builder/verilog_builder/verilog_read.cpp index c790e1b46b942b7386b5d181c12346147742de4c..2536c04baa4ad8abd5d8269156dbaf6fe3b67f7a 100644 --- a/src/database/manager/builder/verilog_builder/verilog_read.cpp +++ b/src/database/manager/builder/verilog_builder/verilog_read.cpp @@ -634,7 +634,8 @@ int32_t RustVerilogRead::build_assign() } } else if (rust_is_concat_expr(left_net_expr) && rust_is_concat_expr(right_net_expr)) { - std::function(RustVec&)> get_concat_net_names = [&get_concat_net_names](RustVec& verilog_id_concat) -> std::vector { + std::function(RustVec&)> get_concat_net_names + = [&get_concat_net_names](RustVec& verilog_id_concat) -> std::vector { std::vector concat_net_names; void* one_net_expr; FOREACH_VEC_ELEM(&verilog_id_concat, void, one_net_expr) diff --git a/src/evaluation/README.md b/src/evaluation/README.md index 6c63cb3bf7cedb227e6575875e4628d43aca7fa8..e3c6945606d02b7478d1b54f5b2a7aba54c785ab 100644 --- a/src/evaluation/README.md +++ b/src/evaluation/README.md @@ -55,12 +55,16 @@ evaluation/api文件夹提供外部使用的接口,根据指标进行分类, | `cellDensityMap(DensityCells, DensityRegion, int, string )` | 单元列表,区域信息,网格粒度,设计阶段名称 | `struct{macro_density,stdcell_density,allcell_density}` | 根据传入的数据结构直接计算各类版图级单元密度,输出二维图 | | `pinDensityMap(DensityPins, DensityRegion, int, string, bool )` | 引脚列表,区域信息,网格粒度,设计阶段名称,当前网格是否累加周围一圈网格数值 | `struct{macro_pin,stdcell_pin,allcell_pin}` | 根据传入的数据结构直接计算各类版图级引脚密度,输出二维图 | | `netDensityMap(DensityNets, DensityRegion, int, string, bool )` | 线网列表,区域信息,网格粒度,设计阶段名称,当前网格是否累加周围一圈网格数值 | `struct{local_net,global_net,allnet}` | 根据传入的数据结构直接计算各类版图级线网密度,输出二维图 | -| `macroMarginMap(int)` | 网格粒度 | `struct{horizontal, vertical, union}` | 从iDB获取数据,构建评估器数据,计算版图级宏单元间隙,输出二维图 | -| `macroMarginMap(DensityCells, DensityRegion, DensityRegion, int)` | 宏单元列表,Die信息,Core信息,网格粒度 | `struct{horizontal, vertical, union}` | 根据传入的数据结构直接计算版图级宏单元间隙,输出二维图 | +| `macroMarginMap(int, string)` | 网格粒度, 设计阶段名称 | `struct{horizontal, vertical, union}` | 从iDB获取数据,构建评估器数据,计算版图级宏单元间隙,输出二维图 | +| `macroMarginMap(DensityCells, DensityRegion, DensityRegion, int, string)` | 宏单元列表,Die信息,Core信息,网格粒度,设计阶段名称 | `struct{horizontal, vertical, union}` | 根据传入的数据结构直接计算版图级宏单元间隙,输出二维图 | | `patchPinDensity(patch_id_coord_map)` | 所有网格(patch)组成的`map` | `map` | 根据传入的网格划分信息,利用iDB初始化版图数据,返回网格id及其对应的单元引脚密度 | | `patchCellDensity(patch_id_coord_map)` | 所有网格(patch)组成的`map` | `map` | 根据传入的网格划分信息,利用iDB初始化版图数据,返回网格id及其对应的单元密度 | | `patchNetDensity(patch_id_coord_map)` | 所有网格(patch)组成的`map` | `map` | 根据传入的网格划分信息,利用iDB初始化版图数据,返回网格id及其对应的线网密度 | | `patchMacroMargin(patch_id_coord_map)` | 所有网格(patch)组成的`map` | `map` | 根据传入的网格划分信息,利用iDB初始化版图数据,返回网格id及其对应的宏单元间隙密度 | +| `cellDensity(int, int, string)` | 水平划分的网格数,竖直划分的网格数,密度图输出路径 | `struct{max_density, avg_density}` | 根据传入的网格划分信息,利用iDB初始化版图数据,输出密度图,返回最大单元密度和平均单元密度 | +| `pinDensity(int, int, string)` | 水平划分的网格数,竖直划分的网格数,密度图输出路径 | `struct{max_density, avg_density}` | 根据传入的网格划分信息,利用iDB初始化版图数据,输出密度图,返回最大引脚密度和平均引脚密度 | +| `netDensity(int, int, string)` | 水平划分的网格数,竖直划分的网格数,密度图输出路径 | `struct{max_density, avg_density}` | 根据传入的网格划分信息,利用iDB初始化版图数据,输出密度图,返回最大线网密度和平均线网密度 | + ### Congestion API @@ -104,7 +108,9 @@ evaluation/api文件夹提供外部使用的接口,根据指标进行分类, | `findBBoxUx(string)` | 线网名称 | 线网外接矩形右上角x坐标 | 根据线网名称,查找线网外接矩形右上角x坐标 | | `findBBoxUy(string)` | 线网名称 | 线网外接矩形右上角y坐标 | 根据线网名称,查找线网外接矩形右上角y坐标 | | `egrUnionMap(string,string)` | 设计阶段名称(用于文件名),iRT生成拥塞的文件目录 | 二维拥塞图路径 | 启动iRT进行早期全局布线且结果保存到指定拥塞文件目录下,计算各个布线层的GCell拥塞,输出按照所有方向累加后的二维拥塞图路径 | - +| `rudyCongestion(int,int,string)` | 网格划分列数,网格划分行数,拥塞图保存路径 | 最大拥塞值,总拥塞值 | 根据划分的网格数计算RUDY拥塞,保存拥塞图,返回最大拥塞和总拥塞 | +| `lutRudyCongestion(int,int,string)` | 网格划分列数,网格划分行数,拥塞图保存路径 | 最大拥塞值,总拥塞值 | 根据划分的网格数计算LUT-RUDY拥塞(根据引脚个数、引脚分布、线网长宽比查表近似线长),保存拥塞图,返回最大拥塞和总拥塞 | +| `egrCongestion(string)` | 拥塞图保存路径 | 最大溢出值,总溢出值 | 调用egr评估拥塞,保存拥塞图,返回最大溢出值和总溢出值 | ### Timing(Power) API 支持通过五种不同的线长模型(HPWL,FLUTE,SALT,EGR,DR)完成RC Tree的构建,并进行静态时序分析和功耗分析。支持时序、功耗各项指标的计算,支持设计级、线网级、路径级的时序和功耗指标查询。值得注意的是,时序评估器尚未支持直接基于布线结果(route.def)构建RCTree进行时序和功耗分析,目前EGR和DR需要调用iRT分别执行完对应GR和DR的流程,较为耗时。 @@ -141,6 +147,6 @@ evaluation/api文件夹提供外部使用的接口,根据指标进行分类, | 接口名 | 输入参数 | 返回类型 | 底层逻辑 | | :-----: | :--------------------------------------: | :------------------------------------------: | :------------------------------------------: | -| `save_pl_eval_union(string, string, int)` | Jsonl文件保存路径,CSV文件保存路径,网格粒度 | `bool` | 分别保存`Place`阶段汇总性特征到Jsonl文件(设计级)和CSV文件(线网级) | -| `save_cts_eval_union(string, string, int)` | Jsonl文件保存路径,CSV文件保存路径,网格粒度 | `bool` | 分别保存`CTS`阶段汇总性特征到Jsonl文件(设计级)和CSV文件(线网级) | +| `save_pl_eval(string, int)` | Json文件保存路径,网格粒度 | `bool` | 保存`Place`阶段汇总性特征到Json文件 | +| `save_cts_eval(string, int)` | Json文件保存路径, 网格粒度 | `bool` | 保存`CTS`阶段汇总性特征到Json文件 | diff --git a/src/evaluation/api/congestion_api.cpp b/src/evaluation/api/congestion_api.cpp index bc4e06676a71eb27d34b7b9c5eeb887f3ef34131..99cdd269733838a111e30e3bd19314e07b3560d1 100644 --- a/src/evaluation/api/congestion_api.cpp +++ b/src/evaluation/api/congestion_api.cpp @@ -158,6 +158,40 @@ UtilizationSummary CongestionAPI::rudyUtilization(std::string stage, std::string return utilization_summary; } +CongestionValue CongestionAPI::rudyCongestion(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) +{ + CongestionValue congestion_value; + + EVAL_CONGESTION_INST->initIDB(); + congestion_value = EVAL_CONGESTION_INST->calRUDY(bin_cnt_x, bin_cnt_y, save_path); + EVAL_CONGESTION_INST->destroyIDB(); + + return congestion_value; +} + +CongestionValue CongestionAPI::lutRudyCongestion(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) +{ + CongestionValue congestion_value; + + EVAL_CONGESTION_INST->initIDB(); + congestion_value = EVAL_CONGESTION_INST->calLUTRUDY(bin_cnt_x, bin_cnt_y, save_path); + EVAL_CONGESTION_INST->destroyIDB(); + + return congestion_value; +} + +CongestionValue CongestionAPI::egrCongestion(const std::string& save_path) +{ + CongestionValue congestion_value; + + EVAL_CONGESTION_INST->initEGR(); + congestion_value = EVAL_CONGESTION_INST->calEGRCongestion(save_path); + EVAL_CONGESTION_INST->destroyEGR(); + + return congestion_value; +} + + void CongestionAPI::evalNetInfo() { EVAL_CONGESTION_INST->initIDB(); @@ -269,4 +303,45 @@ std::string CongestionAPI::egrUnionMap(std::string stage, std::string rt_dir_pat return union_egr_map_path; } +std::map>> CongestionAPI::getEGRMap(bool is_run_egr) +{ + return EVAL_CONGESTION_INST->getDemandSupplyDiffMap(is_run_egr); +} + + +std::map CongestionAPI::patchRUDYCongestion(std::map, std::pair>> patch_coords) +{ + std::map patch_rudy_congestion; + + EVAL_CONGESTION_INST->initIDB(); + + CongestionEval congestion_eval; + patch_rudy_congestion = congestion_eval.patchRUDYCongestion(EVAL_CONGESTION_INST->getCongestionNets(), + patch_coords); + EVAL_CONGESTION_INST->destroyIDB(); + + return patch_rudy_congestion; +} + +std::map CongestionAPI::patchEGRCongestion(std::map, std::pair>> patch_coords) +{ + std::map patch_egr_congestion; + + CongestionEval congestion_eval; + patch_egr_congestion = congestion_eval.patchEGRCongestion(patch_coords); + + return patch_egr_congestion; +} + +std::map> CongestionAPI::patchLayerEGRCongestion(std::map, std::pair>> patch_coords) +{ + std::map> patch_layer_egr_congestion; + + CongestionEval congestion_eval; + patch_layer_egr_congestion = congestion_eval.patchLayerEGRCongestion(patch_coords); + + return patch_layer_egr_congestion; +} + + } // namespace ieval diff --git a/src/evaluation/api/congestion_api.h b/src/evaluation/api/congestion_api.h index d34415965313f4f0f2b9aa84372fdb45ecfc5a51..76673dd9ba28249aed76aca33e379a1c94eda80f 100644 --- a/src/evaluation/api/congestion_api.h +++ b/src/evaluation/api/congestion_api.h @@ -7,6 +7,8 @@ #pragma once +#include + #include "congestion_db.h" namespace ieval { @@ -34,6 +36,15 @@ class CongestionAPI RUDYMapSummary rudyMap(std::string stage, CongestionNets congestion_nets, CongestionRegion region, int32_t grid_size); UtilizationSummary rudyUtilization(std::string stage, std::string rudy_dir_path, bool use_lut = false); + std::map>> getEGRMap(bool is_run_egr = true); + std::map patchRUDYCongestion(std::map, std::pair>> patch_coords); + std::map patchEGRCongestion(std::map, std::pair>> patch_coords); + std::map> patchLayerEGRCongestion(std::map, std::pair>> patch_coords); + + CongestionValue rudyCongestion(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); + CongestionValue lutRudyCongestion(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); + CongestionValue egrCongestion(const std::string& save_path = ""); + void evalNetInfo(); void evalNetInfoPure(); int findPinNumber(std::string net_name); diff --git a/src/evaluation/api/density_api.cpp b/src/evaluation/api/density_api.cpp index 9e0897266f28bc5508498860784242bdcea110c0..4e2081184430d15e9fc1d23f748132ce16d23e93 100644 --- a/src/evaluation/api/density_api.cpp +++ b/src/evaluation/api/density_api.cpp @@ -137,9 +137,10 @@ NetMapSummary DensityAPI::netDensityMap(DensityNets nets, DensityRegion region, MacroCustomizedSummary DensityAPI::macroCustomizedMap(int32_t grid_size) { MacroCustomizedSummary macro_customized_summary; + std::string stage = "place"; // Default stage, can be modified as needed EVAL_DENSITY_INST->initIDB(); - macro_customized_summary.margin_summary = macroMarginMap(grid_size); + macro_customized_summary.margin_summary = macroMarginMap(grid_size, stage); macro_customized_summary.macro_channel = macroChannelMap(grid_size); macro_customized_summary.max_continuous_space = macroMaxContinuousSpaceMap(grid_size); macro_customized_summary.macro_hierarchy = macroHierarchyMap(grid_size); @@ -148,14 +149,14 @@ MacroCustomizedSummary DensityAPI::macroCustomizedMap(int32_t grid_size) return macro_customized_summary; } -MacroMarginSummary DensityAPI::macroMarginMap(int32_t grid_size) +MacroMarginSummary DensityAPI::macroMarginMap(int32_t grid_size, std::string stage) { MacroMarginSummary macro_margin_summary; EVAL_DENSITY_INST->initIDBRegion(); EVAL_DENSITY_INST->initIDBCells(); macro_margin_summary = macroMarginMap(EVAL_DENSITY_INST->getDensityCells(), EVAL_DENSITY_INST->getDensityRegion(), - EVAL_DENSITY_INST->getDensityRegionCore(), grid_size * EVAL_DENSITY_INST->getRowHeight()); + EVAL_DENSITY_INST->getDensityRegionCore(), grid_size * EVAL_DENSITY_INST->getRowHeight(), stage); return macro_margin_summary; } @@ -186,14 +187,14 @@ std::string DensityAPI::macroHierarchyMap(int32_t grid_size) return macro_hierarchy; } -MacroMarginSummary DensityAPI::macroMarginMap(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size) +MacroMarginSummary DensityAPI::macroMarginMap(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size, std::string stage) { MacroMarginSummary macro_margin_summary; DensityEval density_eval; - macro_margin_summary.horizontal_margin = density_eval.evalHorizonMargin(cells, die, core, grid_size); - macro_margin_summary.vertical_margin = density_eval.evalVerticalMargin(cells, die, core, grid_size); - macro_margin_summary.union_margin = density_eval.evalAllMargin(cells, die, core, grid_size); + macro_margin_summary.horizontal_margin = density_eval.evalHorizonMargin(cells, die, core, grid_size, stage); + macro_margin_summary.vertical_margin = density_eval.evalVerticalMargin(cells, die, core, grid_size, stage); + macro_margin_summary.union_margin = density_eval.evalAllMargin(cells, die, core, grid_size, stage); return macro_margin_summary; } @@ -205,4 +206,78 @@ std::string DensityAPI::macroChannelMap(DensityCells cells, DensityRegion die, D return macro_channel_map; } +std::map DensityAPI::patchPinDensity(std::map, std::pair>> patch_coords) +{ + std::map patch_pin_density; + + EVAL_DENSITY_INST->initIDB(); + + DensityEval density_eval; + patch_pin_density = density_eval.patchPinDensity(EVAL_DENSITY_INST->getDensityPins(), + patch_coords); + return patch_pin_density; +} + +std::map DensityAPI::patchCellDensity(std::map, std::pair>> patch_coords) +{ + std::map patch_cell_density; + + EVAL_DENSITY_INST->initIDB(); + + DensityEval density_eval; + patch_cell_density = density_eval.patchCellDensity(EVAL_DENSITY_INST->getDensityCells(), + patch_coords); + return patch_cell_density; +} + + +std::map DensityAPI::patchNetDensity(std::map, std::pair>> patch_coords) +{ + std::map patch_net_density; + + EVAL_DENSITY_INST->initIDB(); + + DensityEval density_eval; + patch_net_density = density_eval.patchNetDensity(EVAL_DENSITY_INST->getDensityNets(), + patch_coords); + + return patch_net_density; +} + +std::map DensityAPI::patchMacroMargin(std::map, std::pair>> patch_coords) +{ + std::map patch_macro_margin; + + EVAL_DENSITY_INST->initIDB(); + + DensityEval density_eval; + patch_macro_margin = density_eval.patchMacroMargin(EVAL_DENSITY_INST->getDensityCells(), EVAL_DENSITY_INST->getDensityRegionCore(), patch_coords); + + return patch_macro_margin; +} + +DensityValue DensityAPI::cellDensity(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) +{ + EVAL_DENSITY_INST->initIDB(); + DensityValue density_value = EVAL_DENSITY_INST->calCellDensity(bin_cnt_x, bin_cnt_y, save_path); + EVAL_DENSITY_INST->destroyIDB(); + return density_value; +} + +DensityValue DensityAPI::pinDensity(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) +{ + EVAL_DENSITY_INST->initIDB(); + DensityValue density_value = EVAL_DENSITY_INST->calPinDensity(bin_cnt_x, bin_cnt_y, save_path); + EVAL_DENSITY_INST->destroyIDB(); + return density_value; +} + +DensityValue DensityAPI::netDensity(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) +{ + EVAL_DENSITY_INST->initIDB(); + DensityValue density_value = EVAL_DENSITY_INST->calNetDensity(bin_cnt_x, bin_cnt_y, save_path); + EVAL_DENSITY_INST->destroyIDB(); + return density_value; +} + } // namespace ieval \ No newline at end of file diff --git a/src/evaluation/api/density_api.h b/src/evaluation/api/density_api.h index 635704a29da420b5c059fc7cb2b482bfab7c015c..9b25772a177612ec7229fdf0c7354c8bfbd5cfec 100644 --- a/src/evaluation/api/density_api.h +++ b/src/evaluation/api/density_api.h @@ -8,6 +8,7 @@ #pragma once #include "density_db.h" +#include #define DENSITY_API_INST (ieval::DensityAPI::getInst()) @@ -30,8 +31,8 @@ class DensityAPI PinMapSummary pinDensityMap(DensityPins pins, DensityRegion region, int32_t grid_size, std::string stage, bool neighbor); NetMapSummary netDensityMap(DensityNets nets, DensityRegion region, int32_t grid_size, std::string stage, bool neighbor); - MacroMarginSummary macroMarginMap(int32_t grid_size = 1); - MacroMarginSummary macroMarginMap(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size); + MacroMarginSummary macroMarginMap(int32_t grid_size = 1, std::string stage = "place"); + MacroMarginSummary macroMarginMap(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size, std::string stage); MacroCustomizedSummary macroCustomizedMap(int32_t grid_size = 1); std::string macroChannelMap(int32_t grid_size = 1); @@ -39,6 +40,15 @@ class DensityAPI std::string macroMaxContinuousSpaceMap(int32_t grid_size = 1); std::string macroHierarchyMap(int32_t grid_size = 1); + std::map patchPinDensity(std::map, std::pair>> patch_coords); + std::map patchCellDensity(std::map, std::pair>> patch_coords); + std::map patchNetDensity(std::map, std::pair>> patch_coords); + std::map patchMacroMargin(std::map, std::pair>> patch_coords); + + DensityValue cellDensity(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); + DensityValue pinDensity(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); + DensityValue netDensity(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); + private: static DensityAPI* _density_api_inst; }; diff --git a/src/evaluation/api/timing_api.cc b/src/evaluation/api/timing_api.cc index 1606138b479b403d63b82feee836f61f28024dee..29d5812115660908ba86178941715903f73603c9 100644 --- a/src/evaluation/api/timing_api.cc +++ b/src/evaluation/api/timing_api.cc @@ -29,11 +29,26 @@ void TimingAPI::runSTA() EVAL_STA_INST->runSTA(); } +void TimingAPI::runVecSTA(ivec::VecLayout* vec_layout) +{ + EVAL_STA_INST->runVecSTA(vec_layout); +} + void TimingAPI::evalTiming(const std::string& routing_type, const bool& rt_done) { EVAL_STA_INST->evalTiming(routing_type, rt_done); } +TimingWireGraph* TimingAPI::getTimingWireGraph() +{ + return EVAL_STA_INST->getTimingWireGraph(); +} + +TimingInstanceGraph* TimingAPI::getTimingInstanceGraph() +{ + return EVAL_STA_INST->getTimingInstanceGraph(); +} + void TimingAPI::destroyInst() { ieval::TimingEval::destroyInst(); @@ -104,4 +119,19 @@ bool TimingAPI::isClockNet(const std::string& net_name) const return EVAL_STA_INST->isClockNet(net_name); } +std::map TimingAPI::patchTimingMap(std::map, std::pair>>& patch_xy_map) +{ + return EVAL_STA_INST->patchTimingMap(patch_xy_map); +} + +std::map TimingAPI::patchPowerMap(std::map, std::pair>>& patch_xy_map) +{ + return EVAL_STA_INST->patchPowerMap(patch_xy_map); +} + +std::map TimingAPI::patchIRDropMap(std::map, std::pair>>& patch_xy_map) +{ + return EVAL_STA_INST->patchIRDropMap(patch_xy_map); +} + } // namespace ieval \ No newline at end of file diff --git a/src/evaluation/api/timing_api.hh b/src/evaluation/api/timing_api.hh index dbeb2c05651ddb3b7f85aa71dc6ba51fea27e2d0..71d28b25a73f41ee1db80be109382067883cd180 100644 --- a/src/evaluation/api/timing_api.hh +++ b/src/evaluation/api/timing_api.hh @@ -14,7 +14,18 @@ namespace ista { enum class AnalysisMode; } + +namespace ivec { +class VecLayout; +} + +#define TimingPower_API_INST (ieval::TimingAPI::getInst()) + namespace ieval { + +class TimingWireGraph; +class TimingInstanceGraph; + class TimingAPI { public: @@ -25,7 +36,10 @@ class TimingAPI static TimingAPI* getInst(); void runSTA(); + void runVecSTA(ivec::VecLayout* vec_layout); void evalTiming(const std::string& routing_type, const bool& rt_done = false); + TimingWireGraph* getTimingWireGraph(); + TimingInstanceGraph* getTimingInstanceGraph(); static void destroyInst(); @@ -48,6 +62,10 @@ class TimingAPI bool isClockNet(const std::string& net_name) const; + std::map patchTimingMap(std::map, std::pair>>& patch_xy_map); + std::map patchPowerMap(std::map, std::pair>>& patch_xy_map); + std::map patchIRDropMap(std::map, std::pair>>& patch_xy_map); + private: static TimingAPI* _timing_api; }; diff --git a/src/evaluation/api/wirelength_api.cpp b/src/evaluation/api/wirelength_api.cpp index ed917978c92ae4e77b302c73440d271d2b256071..5546f569bc7e034b481677db4f4715a1f3980df5 100644 --- a/src/evaluation/api/wirelength_api.cpp +++ b/src/evaluation/api/wirelength_api.cpp @@ -175,4 +175,16 @@ int32_t WirelengthAPI::findNetGRWL(std::string net_name) return EVAL_WIRELENGTH_INST->findGRWL(net_name); } +void WirelengthAPI::evalNetFlute() +{ + EVAL_WIRELENGTH_INST->initIDB(); + EVAL_WIRELENGTH_INST->initFlute(); + + EVAL_WIRELENGTH_INST->evalNetFlute(); + + EVAL_WIRELENGTH_INST->destroyIDB(); + EVAL_WIRELENGTH_INST->destroyFlute(); +} + + } // namespace ieval \ No newline at end of file diff --git a/src/evaluation/api/wirelength_api.h b/src/evaluation/api/wirelength_api.h index 155f73fe3cb48165940e80b681fc45b11eba2a1c..e72765cca314348f803671ab235a187c9aaccc68 100644 --- a/src/evaluation/api/wirelength_api.h +++ b/src/evaluation/api/wirelength_api.h @@ -35,6 +35,7 @@ class WirelengthAPI void evalNetInfo(); void evalNetInfoPure(); + void evalNetFlute(); int32_t findNetHPWL(std::string net_name); int32_t findNetFLUTE(std::string net_name); int32_t findNetGRWL(std::string net_name); diff --git a/src/evaluation/apps/congestion_app.cpp b/src/evaluation/apps/congestion_app.cpp index eb92efa452cf9faa7fa3ecbbb93811cd6be1b35a..d2fef3e6307aac0331e4ea8d34e6dec1fdf899e1 100644 --- a/src/evaluation/apps/congestion_app.cpp +++ b/src/evaluation/apps/congestion_app.cpp @@ -52,6 +52,27 @@ int main(const int argc, const char* argv[]) return 1; } +void TestEgrDataStructure() +{ + std::string congestion_dir = "/home/yhqiu/net_level_collect/benchmark/large_model_test/rt/rt_temp_directory/early_router"; + + ieval::CongestionAPI api; + std::map>> egr_map = api.getEGRMap(); + + for (const auto& pair : egr_map) { + std::cout << "Layer: " << pair.first << std::endl; + const auto& matrix = pair.second; + + for (size_t i = 0; i < matrix.size() && i < 3; ++i) { + for (const auto& value : matrix[i]) { + std::cout << value << " "; + } + std::cout << std::endl; + } + std::cout << std::endl; + } +} + void TestEgrMap() { ieval::CongestionAPI congestion_api; diff --git a/src/evaluation/apps/density_app.cpp b/src/evaluation/apps/density_app.cpp index 44f3300ae1ef895960658cb6d76d18da1316a0ff..a152e801435f617849f4f77a4b42c00de4773b1e 100644 --- a/src/evaluation/apps/density_app.cpp +++ b/src/evaluation/apps/density_app.cpp @@ -173,8 +173,9 @@ void TestMarginMap() cells.push_back(cell2); int32_t grid_size = 25; + std::string stage = "place"; - ieval::MacroMarginSummary macro_margin_summary = density_api.macroMarginMap(cells, die, core, grid_size); + ieval::MacroMarginSummary macro_margin_summary = density_api.macroMarginMap(cells, die, core, grid_size, stage); std::cout << "Horizontal margin: " << macro_margin_summary.horizontal_margin << std::endl; std::cout << "Vertical margin: " << macro_margin_summary.vertical_margin << std::endl; std::cout << "Union margin: " << macro_margin_summary.union_margin << std::endl; diff --git a/src/evaluation/database/congestion_db.h b/src/evaluation/database/congestion_db.h index 0bb6b51d3c9265c1ae55cb0d16d8441a3202ba81..75c44212a890093ecae714168c87f0dd455bd9a3 100644 --- a/src/evaluation/database/congestion_db.h +++ b/src/evaluation/database/congestion_db.h @@ -13,6 +13,12 @@ #include namespace ieval { + +struct CongestionValue { + double max_congestion; + double total_congestion; +}; + struct CongestionPin { int32_t lx; diff --git a/src/evaluation/database/density_db.h b/src/evaluation/database/density_db.h index 0ac57c761d51eb3e1c8156d2c8fa4d12bff18793..355fe63844c0e98fa2f01f4d913877b44a862528 100644 --- a/src/evaluation/database/density_db.h +++ b/src/evaluation/database/density_db.h @@ -14,6 +14,11 @@ namespace ieval { +struct DensityValue { + double max_density; + double avg_density; +}; + struct DensityPin { std::string type; @@ -28,6 +33,7 @@ struct DensityCell int32_t ly; int32_t width; int32_t height; + int id; }; struct DensityNet @@ -36,6 +42,7 @@ struct DensityNet int32_t ly; int32_t ux; int32_t uy; + int id; }; struct DensityRegion diff --git a/src/evaluation/src/module/congestion/CMakeLists.txt b/src/evaluation/src/module/congestion/CMakeLists.txt index 9fa8108512124c7ea462e968fdacf2f3782f5c29..cd8552045b7dfa6f8760273a6ca7c3994d6a9bb8 100644 --- a/src/evaluation/src/module/congestion/CMakeLists.txt +++ b/src/evaluation/src/module/congestion/CMakeLists.txt @@ -4,6 +4,7 @@ add_library(eval_congestion_eval target_link_libraries(eval_congestion_eval PRIVATE + idm eval_util_init_egr eval_util_wirelength_lut eval_util_general_ops diff --git a/src/evaluation/src/module/congestion/congestion_eval.cpp b/src/evaluation/src/module/congestion/congestion_eval.cpp index f37f6c74d0b60a213e9c17e21e5f6026f0ae8df3..841542dc9f4df318cf1a8d2afd750a07c2ec0374 100644 --- a/src/evaluation/src/module/congestion/congestion_eval.cpp +++ b/src/evaluation/src/module/congestion/congestion_eval.cpp @@ -18,6 +18,7 @@ #include #include "general_ops.h" +#include "idm.h" #include "init_egr.h" #include "init_idb.h" #include "wirelength_lut.h" @@ -184,10 +185,6 @@ string CongestionEval::evalEGR(string rt_dir_path, string egr_type, string outpu // << std::endl; // } std::vector target_layers; - std::string dir_path = rt_dir_path + "/early_router/"; - std::filesystem::path parent_path = std::filesystem::path(rt_dir_path).parent_path(); - std::filesystem::path out_file_path = parent_path / output_filename; - if (egr_type == "horizontal" || egr_type == "vertical") { LayerDirection target_direction = (egr_type == "horizontal") ? LayerDirection::Horizontal : LayerDirection::Vertical; for (const auto& [layer, direction] : layer_directions) { @@ -203,6 +200,7 @@ string CongestionEval::evalEGR(string rt_dir_path, string egr_type, string outpu std::vector> sum_matrix; bool is_first_file = true; + std::string dir_path = rt_dir_path + "/early_router/"; for (const auto& entry : std::filesystem::directory_iterator(dir_path)) { std::string filename = entry.path().filename().string(); @@ -237,7 +235,10 @@ string CongestionEval::evalEGR(string rt_dir_path, string egr_type, string outpu } } - std::ofstream out_file(out_file_path); + std::string save_dir = "/egr_congestion_map"; + std::string output_path = createDirPath(save_dir) + "/" + output_filename; + + std::ofstream out_file(output_path); for (const auto& row : sum_matrix) { for (size_t i = 0; i < row.size(); ++i) { out_file << row[i]; @@ -249,7 +250,7 @@ string CongestionEval::evalEGR(string rt_dir_path, string egr_type, string outpu } out_file.close(); - return out_file_path.string(); + return output_path; } string CongestionEval::evalRUDY(CongestionNets nets, CongestionRegion region, int32_t grid_size, string rudy_type, string output_filename) @@ -323,7 +324,14 @@ string CongestionEval::evalRUDY(CongestionNets nets, CongestionRegion region, in } } - std::string output_path = createDirPath("RUDY_map") + "/" + output_filename; + std::string stage; + size_t underscore_pos = output_filename.find('_'); + if (underscore_pos != std::string::npos) { + stage = output_filename.substr(0, underscore_pos); + } + + std::string save_dir = "/RUDY_map"; + std::string output_path = createDirPath(save_dir) + "/" + output_filename; std::ofstream csv_file(output_path); for (size_t row_index = density_grid.size(); row_index-- > 0;) { @@ -435,7 +443,14 @@ string CongestionEval::evalLUTRUDY(CongestionNets nets, CongestionRegion region, } } - std::string output_path = createDirPath("RUDY_map") + "/" + output_filename; + std::string stage; + size_t underscore_pos = output_filename.find('_'); + if (underscore_pos != std::string::npos) { + stage = output_filename.substr(0, underscore_pos); + } + + std::string save_dir = "/RUDY_map"; + std::string output_path = createDirPath(save_dir) + "/" + output_filename; std::ofstream csv_file(output_path); for (size_t row_index = density_grid.size(); row_index-- > 0;) { @@ -573,9 +588,8 @@ int32_t CongestionEval::evalTotalOverflow(string stage, string rt_dir_path, stri } else { return -1; } - std::filesystem::path parent_path = std::filesystem::path(rt_dir_path).parent_path(); - std::filesystem::path file_path = parent_path / file_name; - std::string file_path_str = file_path.string(); + + std::string file_path_str = dmInst->get_config().get_feature_path() + "/egr_congestion_map/" + file_name; std::ifstream file(file_path_str); if (!file.is_open()) { @@ -609,9 +623,8 @@ int32_t CongestionEval::evalMaxOverflow(string stage, string rt_dir_path, string } else { return -1; } - std::filesystem::path parent_path = std::filesystem::path(rt_dir_path).parent_path(); - std::filesystem::path file_path = parent_path / file_name; - std::string file_path_str = file_path.string(); + std::string file_path_str = dmInst->get_config().get_feature_path() + "/egr_congestion_map/" + file_name; + std::ifstream file(file_path_str); if (!file.is_open()) { @@ -646,9 +659,7 @@ float CongestionEval::evalAvgOverflow(string stage, string rt_dir_path, string o } else { return -1; } - std::filesystem::path parent_path = std::filesystem::path(rt_dir_path).parent_path(); - std::filesystem::path file_path = parent_path / file_name; - std::string file_path_str = file_path.string(); + std::string file_path_str = dmInst->get_config().get_feature_path() + "/egr_congestion_map/" + file_name; std::ifstream file(file_path_str); if (!file.is_open()) { @@ -882,6 +893,340 @@ int32_t CongestionEval::getRowHeight() return EVAL_INIT_IDB_INST->getRowHeight(); } +CongestionValue CongestionEval::calRUDY(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) +{ + CongestionRegion region = getCongestionRegion(); + CongestionNets nets = getCongestionNets(); + + std::vector> density_grid(bin_cnt_y, std::vector(bin_cnt_x, 0.0)); + + double grid_size_x = static_cast(region.ux - region.lx) / bin_cnt_x; + double grid_size_y = static_cast(region.uy - region.ly) / bin_cnt_y; + + for (const auto& net : nets) { + int32_t start_row = bin_cnt_y - 1; + int32_t end_row = 0; + int32_t start_col = bin_cnt_x - 1; + int32_t end_col = 0; + int32_t net_lx = INT32_MAX; + int32_t net_ly = INT32_MAX; + int32_t net_ux = INT32_MIN; + int32_t net_uy = INT32_MIN; + + for (const auto& pin : net.pins) { + int32_t pin_col = static_cast((pin.lx - region.lx) / grid_size_x); + int32_t pin_row = static_cast((pin.ly - region.ly) / grid_size_y); + + pin_col = std::max(0, std::min(bin_cnt_x - 1, pin_col)); + pin_row = std::max(0, std::min(bin_cnt_y - 1, pin_row)); + + start_row = std::min(start_row, pin_row); + end_row = std::max(end_row, pin_row); + start_col = std::min(start_col, pin_col); + end_col = std::max(end_col, pin_col); + + net_lx = std::min(net_lx, pin.lx); + net_ly = std::min(net_ly, pin.ly); + net_ux = std::max(net_ux, pin.lx); + net_uy = std::max(net_uy, pin.ly); + } + + double hor_rudy = 0.0; + if (net_uy == net_ly) { + hor_rudy = 1.0; + } else { + hor_rudy = 1.0 / static_cast(net_uy - net_ly); + } + + double ver_rudy = 0.0; + if (net_ux == net_lx) { + ver_rudy = 1.0; + } else { + ver_rudy = 1.0 / static_cast(net_ux - net_lx); + } + + for (int32_t row = start_row; row <= end_row; ++row) { + for (int32_t col = start_col; col <= end_col; ++col) { + double grid_lx = region.lx + col * grid_size_x; + double grid_ly = region.ly + row * grid_size_y; + double grid_ux = std::min(region.lx + (col + 1) * grid_size_x, static_cast(region.ux)); + double grid_uy = std::min(region.ly + (row + 1) * grid_size_y, static_cast(region.uy)); + double grid_area = (grid_ux - grid_lx) * (grid_uy - grid_ly); + + double overlap_lx = std::max(static_cast(net_lx), grid_lx); + double overlap_ly = std::max(static_cast(net_ly), grid_ly); + double overlap_ux = std::min(static_cast(net_ux), grid_ux); + double overlap_uy = std::min(static_cast(net_uy), grid_uy); + + double overlap_area = 0.0; + if (overlap_lx == overlap_ux) { + overlap_area = overlap_uy - overlap_ly; + } else if (overlap_ly == overlap_uy) { + overlap_area = overlap_ux - overlap_lx; + } else { + overlap_area = (overlap_ux - overlap_lx) * (overlap_uy - overlap_ly); + } + + density_grid[row][col] += overlap_area * (hor_rudy + ver_rudy) / grid_area; + } + } + } + + if (!save_path.empty()) { + std::ofstream csv_file(save_path); + if (csv_file.is_open()) { + for (size_t row_index = density_grid.size(); row_index-- > 0;) { + const auto& row = density_grid[row_index]; + for (size_t i = 0; i < row.size(); ++i) { + csv_file << std::fixed << std::setprecision(6) << row[i]; + if (i < row.size() - 1) + csv_file << ","; + } + csv_file << "\n"; + } + csv_file.close(); + } + } + + double max_congestion = 0.0; + double total_congestion = 0.0; + + for (const auto& row : density_grid) { + for (double congestion : row) { + total_congestion += congestion; + max_congestion = std::max(max_congestion, congestion); + } + } + + CongestionValue result; + result.max_congestion = max_congestion; + result.total_congestion = total_congestion; + + return result; + +} + +CongestionValue CongestionEval::calLUTRUDY(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) +{ + CongestionRegion region = getCongestionRegion(); + CongestionNets nets = getCongestionNets(); + + std::vector> density_grid(bin_cnt_y, std::vector(bin_cnt_x, 0.0)); + + double grid_size_x = static_cast(region.ux - region.lx) / bin_cnt_x; + double grid_size_y = static_cast(region.uy - region.ly) / bin_cnt_y; + + for (const auto& net : nets) { + int32_t start_row = bin_cnt_y - 1; + int32_t end_row = 0; + int32_t start_col = bin_cnt_x - 1; + int32_t end_col = 0; + int32_t net_lx = INT32_MAX; + int32_t net_ly = INT32_MAX; + int32_t net_ux = INT32_MIN; + int32_t net_uy = INT32_MIN; + + for (const auto& pin : net.pins) { + int32_t pin_col = static_cast((pin.lx - region.lx) / grid_size_x); + int32_t pin_row = static_cast((pin.ly - region.ly) / grid_size_y); + + pin_col = std::max(0, std::min(bin_cnt_x - 1, pin_col)); + pin_row = std::max(0, std::min(bin_cnt_y - 1, pin_row)); + + start_row = std::min(start_row, pin_row); + end_row = std::max(end_row, pin_row); + start_col = std::min(start_col, pin_col); + end_col = std::max(end_col, pin_col); + + net_lx = std::min(net_lx, pin.lx); + net_ly = std::min(net_ly, pin.ly); + net_ux = std::max(net_ux, pin.lx); + net_uy = std::max(net_uy, pin.ly); + } + + int pin_num = net.pins.size(); + int aspect_ratio = 1; + if (net_ux - net_lx >= net_uy - net_ly && net_uy - net_ly != 0) { + aspect_ratio = std::round((net_ux - net_lx) / static_cast(net_uy - net_ly)); + } else if (net_ux - net_lx < net_uy - net_ly && net_ux - net_lx != 0) { + aspect_ratio = std::round((net_uy - net_ly) / static_cast(net_ux - net_lx)); + } + double l_ness = 0.0; + if (pin_num < 3) { + l_ness = 1.0; + } else if (pin_num <= 15) { + std::vector> point_set; + for (const auto& pin : net.pins) { + point_set.push_back(std::make_pair(pin.lx, pin.ly)); + } + l_ness = calculateLness(point_set, net_lx, net_ux, net_ly, net_uy); + } else { + l_ness = 0.5; + } + + double hor_lutrudy = 0.0; + if (net_uy == net_ly) { + hor_lutrudy = 1.0; + } else { + hor_lutrudy = getLUT(pin_num, aspect_ratio, l_ness) / static_cast(net_uy - net_ly); + } + double ver_lutrudy = 0.0; + if (net_ux == net_lx) { + ver_lutrudy = 1.0; + } else { + ver_lutrudy = getLUT(pin_num, aspect_ratio, l_ness) / static_cast(net_ux - net_lx); + } + + for (int32_t row = start_row; row <= end_row; ++row) { + for (int32_t col = start_col; col <= end_col; ++col) { + double grid_lx = region.lx + col * grid_size_x; + double grid_ly = region.ly + row * grid_size_y; + double grid_ux = std::min(region.lx + (col + 1) * grid_size_x, static_cast(region.ux)); + double grid_uy = std::min(region.ly + (row + 1) * grid_size_y, static_cast(region.uy)); + double grid_area = (grid_ux - grid_lx) * (grid_uy - grid_ly); + + double overlap_lx = std::max(static_cast(net_lx), grid_lx); + double overlap_ly = std::max(static_cast(net_ly), grid_ly); + double overlap_ux = std::min(static_cast(net_ux), grid_ux); + double overlap_uy = std::min(static_cast(net_uy), grid_uy); + + double overlap_area = 0.0; + if (overlap_lx == overlap_ux) { + overlap_area = overlap_uy - overlap_ly; + } else if (overlap_ly == overlap_uy) { + overlap_area = overlap_ux - overlap_lx; + } else { + overlap_area = (overlap_ux - overlap_lx) * (overlap_uy - overlap_ly); + } + + density_grid[row][col] += overlap_area * (hor_lutrudy + ver_lutrudy) / grid_area; + } + } + } + + if (!save_path.empty()) { + std::ofstream csv_file(save_path); + if (csv_file.is_open()) { + for (size_t row_index = density_grid.size(); row_index-- > 0;) { + const auto& row = density_grid[row_index]; + for (size_t i = 0; i < row.size(); ++i) { + csv_file << std::fixed << std::setprecision(6) << row[i]; + if (i < row.size() - 1) + csv_file << ","; + } + csv_file << "\n"; + } + csv_file.close(); + } + } + + double max_congestion = 0.0; + double total_congestion = 0.0; + + for (const auto& row : density_grid) { + for (double congestion : row) { + total_congestion += congestion; + max_congestion = std::max(max_congestion, congestion); + } + } + + CongestionValue result; + result.max_congestion = max_congestion; + result.total_congestion = total_congestion; + + return result; +} + + +CongestionValue CongestionEval::calEGRCongestion(const std::string& save_path) +{ + std::string rt_dir_path = getEGRDirPath(); + + std::unordered_map layer_directions + = EVAL_INIT_EGR_INST->parseLayerDirection(rt_dir_path + "/early_router/route.guide"); + + std::vector target_layers; + for (const auto& [layer, direction] : layer_directions) { + target_layers.push_back(layer); + } + + std::string dir_path = rt_dir_path + "/early_router/"; + std::vector> sum_matrix; + bool is_first_file = true; + + for (const auto& entry : std::filesystem::directory_iterator(dir_path)) { + std::string filename = entry.path().filename().string(); + if (filename.find("overflow_map_") != std::string::npos) { + for (const auto& layer : target_layers) { + if (filename.find(layer) != std::string::npos) { + std::ifstream file(entry.path()); + std::string line; + size_t row = 0; + + while (std::getline(file, line)) { + std::istringstream iss(line); + std::string value; + int col = 0; + + while (std::getline(iss, value, ',')) { + double num_value = std::stod(value); + + if (is_first_file) { + if (row >= sum_matrix.size()) { + sum_matrix.push_back(std::vector()); + } + sum_matrix[row].push_back(num_value); + } else { + if (row < sum_matrix.size() && col < sum_matrix[row].size()) { + sum_matrix[row][col] += num_value; + } + } + col++; + } + row++; + } + is_first_file = false; + file.close(); + break; + } + } + } + } + + if (!save_path.empty()) { + std::ofstream out_file(save_path); + if (out_file.is_open()) { + for (const auto& row : sum_matrix) { + for (size_t i = 0; i < row.size(); ++i) { + out_file << std::fixed << std::setprecision(6) << row[i]; + if (i < row.size() - 1) { + out_file << ","; + } + } + out_file << "\n"; + } + out_file.close(); + } + } + + double max_congestion = 0.0; + double total_congestion = 0.0; + + for (const auto& row : sum_matrix) { + for (double congestion : row) { + total_congestion += congestion; + max_congestion = std::max(max_congestion, congestion); + } + } + + CongestionValue result; + result.max_congestion = max_congestion; + result.total_congestion = total_congestion; + + return result; + +} + void CongestionEval::evalNetInfo() { CongestionNets nets = getCongestionNets(); @@ -939,30 +1284,6 @@ void CongestionEval::evalNetInfo() int32_t bbox_ly = net_ly; int32_t bbox_ux = net_ux; int32_t bbox_uy = net_uy; - // debug - if (net.name == "n664") { - std::cout << "Debug Info for net: " << net.name << "\n"; - std::cout << "x_coords: "; - for (const auto& x : x_coords) { - std::cout << x << " "; - } - std::cout << "\n"; - - std::cout << "y_coords: "; - for (const auto& y : y_coords) { - std::cout << y << " "; - } - std::cout << "\n"; - - std::cout << "x_entropy: " << x_entropy << "\n"; - std::cout << "y_entropy: " << y_entropy << "\n"; - std::cout << "avg_x_nn_distance: " << avg_x_nn_distance << "\n"; - std::cout << "std_x_nn_distance: " << std_x_nn_distance << "\n"; - std::cout << "ratio_x_nn_distance: " << ratio_x_nn_distance << "\n"; - std::cout << "avg_y_nn_distance: " << avg_y_nn_distance << "\n"; - std::cout << "std_y_nn_distance: " << std_y_nn_distance << "\n"; - std::cout << "ratio_y_nn_distance: " << ratio_y_nn_distance << "\n"; - } _name_pin_numer.emplace(net.name, pin_num); _name_aspect_ratio.emplace(net.name, aspect_ratio); @@ -1220,4 +1541,391 @@ void CongestionEval::setEGRDirPath(std::string egr_dir_path) EVAL_INIT_EGR_INST->setEGRDirPath(egr_dir_path); } +std::map>> CongestionEval::getEGRMap(bool is_run_egr) +{ + std::string congestion_dir = dmInst->get_config().get_output_path() + "/rt/rt_temp_directory/early_router"; + + printf("congestion_dir: %s\n", congestion_dir.c_str()); + // check if congestion_dir is empty + // if (is_run_egr == true) { + std::filesystem::path cong_dir_path(congestion_dir); + std::filesystem::path parent_dir_path = cong_dir_path.parent_path(); + + setEGRDirPath(parent_dir_path.string()); + initEGR(); + destroyEGR(); + // } + + std::map>> egr_map; + std::filesystem::path dir_path(congestion_dir); + + // tranverse all files in the directory + for (const auto& entry : std::filesystem::directory_iterator(dir_path)) { + std::string filename = entry.path().filename().string(); + if (filename.find("overflow_map_") == 0) { + // extract layer name + std::string layer_name = filename.substr(13, filename.length() - 17); + + // read file content + std::ifstream file(entry.path()); + std::string line; + std::vector> matrix; + while (std::getline(file, line)) { + std::vector row; + std::istringstream iss(line); + std::string value; + while (std::getline(iss, value, ',')) { + row.push_back(std::stod(value)); + } + matrix.push_back(row); + } + + // save to egr_map + egr_map[layer_name] = matrix; + } + } + + return egr_map; +} + +std::map>> CongestionEval::getDemandSupplyDiffMap(bool is_run_egr) +{ + // 如果未指定目录,使用默认路径 + std::string congestion_dir = dmInst->get_config().get_output_path() + "/rt/rt_temp_directory"; + + if (is_run_egr == true) { + setEGRDirPath(congestion_dir); + initEGR(); + destroyEGR(); + } + + // 构造early_router和supply_analyzer的完整路径 + std::string demand_dir = congestion_dir + "/early_router"; + std::string supply_dir = congestion_dir + "/supply_analyzer"; + + printf("demand_dir: %s\nsupply_dir: %s\n", demand_dir.c_str(), supply_dir.c_str()); + + // 用于存储最终的差值矩阵 + std::map>> diff_map; + // 临时存储demand和supply矩阵 + std::map>> demand_matrices; + std::map>> supply_matrices; + + // 读取demand矩阵 + std::filesystem::path demand_path(demand_dir); + for (const auto& entry : std::filesystem::directory_iterator(demand_path)) { + std::string filename = entry.path().filename().string(); + if (filename.find("demand_map_") == 0) { + // 提取层名 (AP, M1, M2等) + std::string layer_name = filename.substr(11, filename.length() - 15); + + // 读取文件内容 + std::ifstream file(entry.path()); + std::string line; + std::vector> matrix; + while (std::getline(file, line)) { + std::vector row; + std::istringstream iss(line); + std::string value; + while (std::getline(iss, value, ',')) { + row.push_back(std::stod(value)); + } + matrix.push_back(row); + } + // 反转行顺序(转换为左下角原点) + std::reverse(matrix.begin(), matrix.end()); + demand_matrices[layer_name] = matrix; + } + } + + // 读取supply矩阵 + std::filesystem::path supply_path(supply_dir); + for (const auto& entry : std::filesystem::directory_iterator(supply_path)) { + std::string filename = entry.path().filename().string(); + if (filename.find("supply_map_") == 0) { + // 提取层名 (AP, M1, M2等) + std::string layer_name = filename.substr(11, filename.length() - 15); + + // 读取文件内容 + std::ifstream file(entry.path()); + std::string line; + std::vector> matrix; + while (std::getline(file, line)) { + std::vector row; + std::istringstream iss(line); + std::string value; + while (std::getline(iss, value, ',')) { + row.push_back(std::stod(value)); + } + matrix.push_back(row); + } + // 反转行顺序(转换为左下角原点) + std::reverse(matrix.begin(), matrix.end()); + supply_matrices[layer_name] = matrix; + } + } + + // 计算差值矩阵 + for (const auto& [layer_name, demand_matrix] : demand_matrices) { + // 检查该层是否同时存在supply数据 + if (supply_matrices.find(layer_name) != supply_matrices.end()) { + const auto& supply_matrix = supply_matrices[layer_name]; + + // 确保矩阵尺寸相同 + if (demand_matrix.size() == supply_matrix.size() && demand_matrix[0].size() == supply_matrix[0].size()) { + std::vector> diff_matrix; + for (size_t i = 0; i < demand_matrix.size(); ++i) { + std::vector diff_row; + for (size_t j = 0; j < demand_matrix[i].size(); ++j) { + // 计算差值 + diff_row.push_back(demand_matrix[i][j] - supply_matrix[i][j]); + } + diff_matrix.push_back(diff_row); + } + diff_map[layer_name] = diff_matrix; + } else { + printf("Warning: Matrix size mismatch for layer %s\n", layer_name.c_str()); + } + } + } + + return diff_map; +} + +struct CongestionGridIndex +{ + int grid_size_x = EVAL_INIT_IDB_INST->getDieWidth() / 100; + int grid_size_y = EVAL_INIT_IDB_INST->getDieHeight() / 100; + std::unordered_map, std::vector, CongestionPairHash> grid_map; + + void build(const std::vector& nets) + { + for (int i = 0; i < nets.size(); ++i) { + const auto& net = nets[i]; + // 计算net覆盖的网格范围 + int min_x = net.lx / grid_size_x; + int max_x = net.ux / grid_size_x; + int min_y = net.ly / grid_size_y; + int max_y = net.uy / grid_size_y; + // 注册到所有覆盖的网格 + for (int x = min_x; x <= max_x; ++x) { + for (int y = min_y; y <= max_y; ++y) { + grid_map[{x, y}].push_back(i); + } + } + } + } +}; + +std::map CongestionEval::patchRUDYCongestion(CongestionNets nets, + std::map, std::pair>> patch_coords) +{ + // 预计算 + auto net_metadata = precomputeNetData(nets); + CongestionGridIndex index; + index.build(net_metadata); // 构建空间索引 + + std::map patch_rudy_map; + + // 处理每个patch + for (const auto& [patch_id, coord] : patch_coords) { + const auto& [l_range, u_range] = coord; + const int patch_lx = l_range.first, patch_ly = l_range.second; + const int patch_ux = u_range.first, patch_uy = u_range.second; + const int patch_area = (patch_ux - patch_lx) * (patch_uy - patch_ly); + + // 获取覆盖的网格范围 + int min_gx = patch_lx / index.grid_size_x; + int max_gx = patch_ux / index.grid_size_x; + int min_gy = patch_ly / index.grid_size_y; + int max_gy = patch_uy / index.grid_size_y; + + std::unordered_set processed_nets; // 去重 + double rudy = 0.0; + + // 遍历覆盖的网格 + for (int gx = min_gx; gx <= max_gx; ++gx) { + for (int gy = min_gy; gy <= max_gy; ++gy) { + auto it = index.grid_map.find({gx, gy}); + if (it == index.grid_map.end()) + continue; + + // 处理该网格内的候选net + for (int net_id : it->second) { + if (processed_nets.count(net_id)) + continue; + processed_nets.insert(net_id); + + const auto& net = net_metadata[net_id]; + // 快速边界检查 + if (net.ux <= patch_lx || net.lx >= patch_ux || net.uy <= patch_ly || net.ly >= patch_uy) + continue; + + // 计算重叠区域 + const int overlap_lx = std::max(net.lx, patch_lx); + const int overlap_ly = std::max(net.ly, patch_ly); + const int overlap_ux = std::min(net.ux, patch_ux); + const int overlap_uy = std::min(net.uy, patch_uy); + + const int overlap_width = overlap_ux - overlap_lx; + const int overlap_height = overlap_uy - overlap_ly; + if (overlap_width <= 0 || overlap_height <= 0) + continue; + + // 累加RUDY值(使用预计算结果) + rudy += (overlap_width * overlap_height) * (net.hor_rudy + net.ver_rudy) / patch_area; + } + } + } + patch_rudy_map[patch_id] = rudy; + } + return patch_rudy_map; +} + +std::map CongestionEval::patchEGRCongestion(std::map, std::pair>> patch_coords) +{ + std::map patch_egr_congestion; + + // 获取各层拥塞数据 + auto congestion_layer_map = getDemandSupplyDiffMap(); + if (congestion_layer_map.empty()) { + return patch_egr_congestion; + } + + // 动态获取矩阵尺寸(取第一个有效层的尺寸) + const auto& first_matrix = congestion_layer_map.begin()->second; + const size_t matrix_rows = first_matrix.size(); + const size_t matrix_cols = matrix_rows > 0 ? first_matrix[0].size() : 0; + + if (matrix_rows == 0 || matrix_cols == 0) { + std::cerr << "Error: Empty congestion matrix" << std::endl; + return patch_egr_congestion; + } + + // 步骤1:创建累加矩阵 + std::vector> total_congestion(matrix_rows, std::vector(matrix_cols, 0)); + for (const auto& [layer, matrix] : congestion_layer_map) { + for (size_t row = 0; row < matrix_rows; ++row) { + for (size_t col = 0; col < matrix_cols; ++col) { + total_congestion[row][col] += matrix[row][col]; + } + } + } + + // 步骤2:获取物理坐标范围 + int max_phy_x = 0, max_phy_y = 0; + for (const auto& [id, coords] : patch_coords) { + max_phy_x = std::max(max_phy_x, coords.second.first); // 物理坐标最大值X + max_phy_y = std::max(max_phy_y, coords.second.second); // 物理坐标最大值Y + } + + // 步骤3:建立映射关系 + for (const auto& [patch_id, coords] : patch_coords) { + const auto& [left_bottom, right_top] = coords; + const auto& [phy_x1, phy_y1] = left_bottom; + const auto& [phy_x2, phy_y2] = right_top; + + // 计算中心点坐标(物理坐标) + const double center_phy_x = (phy_x1 + phy_x2) / 2.0; + const double center_phy_y = (phy_y1 + phy_y2) / 2.0; + + // 映射到矩阵行列索引 + const int matrix_row + = std::clamp(static_cast((center_phy_y / max_phy_y) * (matrix_rows - 1)), 0, static_cast(matrix_rows - 1)); + + const int matrix_col + = std::clamp(static_cast((center_phy_x / max_phy_x) * (matrix_cols - 1)), 0, static_cast(matrix_cols - 1)); + + // 存储结果 + patch_egr_congestion[patch_id] = total_congestion[matrix_row][matrix_col]; + } + + return patch_egr_congestion; +} + +std::map> CongestionEval::patchLayerEGRCongestion( + std::map, std::pair>> patch_coords) +{ + // 返回结构: patch_id -> {layer_name -> congestion_value} + std::map> patch_layer_congestion; + + // 获取各层拥塞数据 + auto congestion_layer_map = getDemandSupplyDiffMap(false); + if (congestion_layer_map.empty()) { + return patch_layer_congestion; + } + + // 动态获取矩阵尺寸(取第一个有效层的尺寸) + const auto& first_matrix = congestion_layer_map.begin()->second; + const size_t matrix_rows = first_matrix.size(); + const size_t matrix_cols = matrix_rows > 0 ? first_matrix[0].size() : 0; + + if (matrix_rows == 0 || matrix_cols == 0) { + std::cerr << "Error: Empty congestion matrix" << std::endl; + return patch_layer_congestion; + } + + // 获取物理坐标范围 + int max_phy_x = 0, max_phy_y = 0; + for (const auto& [id, coords] : patch_coords) { + max_phy_x = std::max(max_phy_x, coords.second.first); // 物理坐标最大值X + max_phy_y = std::max(max_phy_y, coords.second.second); // 物理坐标最大值Y + } + + // 为每个patch的每一层建立映射关系 + for (const auto& [patch_id, coords] : patch_coords) { + const auto& [left_bottom, right_top] = coords; + const auto& [phy_x1, phy_y1] = left_bottom; + const auto& [phy_x2, phy_y2] = right_top; + + // 计算中心点坐标(物理坐标) + const double center_phy_x = (phy_x1 + phy_x2) / 2.0; + const double center_phy_y = (phy_y1 + phy_y2) / 2.0; + + // 映射到矩阵行列索引 + const int matrix_row + = std::clamp(static_cast((center_phy_y / max_phy_y) * (matrix_rows - 1)), 0, static_cast(matrix_rows - 1)); + + const int matrix_col + = std::clamp(static_cast((center_phy_x / max_phy_x) * (matrix_cols - 1)), 0, static_cast(matrix_cols - 1)); + + // 为每一层存储拥塞值 + std::map layer_congestion; + for (const auto& [layer_name, congestion_matrix] : congestion_layer_map) { + layer_congestion[layer_name] = congestion_matrix[matrix_row][matrix_col]; + } + + patch_layer_congestion[patch_id] = layer_congestion; + } + + return patch_layer_congestion; +} + +std::vector CongestionEval::precomputeNetData(const CongestionNets& nets) +{ + std::vector metadata; + metadata.reserve(nets.size()); + + for (const auto& net : nets) { + NetMetadata md; + // 计算边界框 + md.lx = INT32_MAX; + md.ly = INT32_MAX; + md.ux = INT32_MIN; + md.uy = INT32_MIN; + for (const auto& pin : net.pins) { + md.lx = std::min(md.lx, pin.lx); + md.ly = std::min(md.ly, pin.ly); + md.ux = std::max(md.ux, pin.lx); + md.uy = std::max(md.uy, pin.ly); + } + // 预计算RUDY因子 + md.hor_rudy = (md.uy == md.ly) ? 1.0 : 1.0 / (md.uy - md.ly); + md.ver_rudy = (md.ux == md.lx) ? 1.0 : 1.0 / (md.ux - md.lx); + + metadata.push_back(md); + } + return metadata; +} + } // namespace ieval \ No newline at end of file diff --git a/src/evaluation/src/module/congestion/congestion_eval.h b/src/evaluation/src/module/congestion/congestion_eval.h index b6bb8bb6303b27983a56a9bf1b93ad567837ebb0..c28e4bec0e185af96d102b01fd08b45c373a593a 100644 --- a/src/evaluation/src/module/congestion/congestion_eval.h +++ b/src/evaluation/src/module/congestion/congestion_eval.h @@ -7,15 +7,34 @@ #pragma once +#include #include +#include #include "congestion_db.h" -#include "map" namespace ieval { using namespace ::std; +struct NetMetadata +{ + int32_t lx, ly, ux, uy; // 预计算的net边界框 + double hor_rudy, ver_rudy; // 预计算的RUDY因子 +}; + +// 辅助哈希函数 +struct CongestionPairHash +{ + template + size_t operator()(const std::pair& p) const + { + auto hash1 = std::hash{}(p.first); + auto hash2 = std::hash{}(p.second); + return hash1 ^ (hash2 << 1); + } +}; + class CongestionEval { public: @@ -64,6 +83,10 @@ class CongestionEval CongestionNets getCongestionNets(); CongestionRegion getCongestionRegion(); + CongestionValue calRUDY(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); + CongestionValue calLUTRUDY(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); + CongestionValue calEGRCongestion(const std::string& save_path = ""); + void evalNetInfo(); int findPinNumber(std::string net_name); int findAspectRatio(std::string net_name); @@ -89,6 +112,14 @@ class CongestionEval std::string getDefaultOutputDir(); void setEGRDirPath(std::string egr_dir_path); + std::map>> getEGRMap(bool is_run_egr = true); + std::map>> getDemandSupplyDiffMap(bool is_run_egr = true); + std::map patchRUDYCongestion(CongestionNets nets, + std::map, std::pair>> patch_coords); + std::map patchEGRCongestion(std::map, std::pair>> patch_coords); + std::map> patchLayerEGRCongestion( + std::map, std::pair>> patch_coords); + private: static CongestionEval* _congestion_eval; @@ -125,6 +156,8 @@ class CongestionEval float evalAvgOverflow(string stage, string rt_dir_path, string overflow_type); float evalMaxUtilization(string stage, string rudy_dir_path, string utilization_type, bool use_lut = false); float evalAvgUtilization(string stage, string rudy_dir_path, string utilization_type, bool use_lut = false); + std::vector precomputeNetData(const CongestionNets& nets); + double calculateEntropy(const std::vector& coords, int bin_count); std::tuple calculateNearestNeighborStats(const std::vector& coords); }; diff --git a/src/evaluation/src/module/density/density_eval.cpp b/src/evaluation/src/module/density/density_eval.cpp index da515ad8b080e23dfcb89ca5bab5144997b1f1b0..fe1e53954ca3e6548442002975adfa5ca36b0e1e 100644 --- a/src/evaluation/src/module/density/density_eval.cpp +++ b/src/evaluation/src/module/density/density_eval.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "general_ops.h" #include "init_idb.h" @@ -94,19 +95,19 @@ std::string DensityEval::evalAllNetDensity(DensityNets nets, DensityRegion regio return evalNetDensity(nets, region, grid_size, neighbor, "all", stage + "_allnet_density.csv"); } -std::string DensityEval::evalHorizonMargin(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size) +std::string DensityEval::evalHorizonMargin(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size, std::string stage) { - return evalMargin(cells, die, core, grid_size, "horizontal", "horizontal_margin.csv"); + return evalMargin(cells, die, core, grid_size, "horizontal", stage + "_horizontal_margin.csv"); } -std::string DensityEval::evalVerticalMargin(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size) +std::string DensityEval::evalVerticalMargin(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size, std::string stage) { - return evalMargin(cells, die, core, grid_size, "vertical", "vertical_margin.csv"); + return evalMargin(cells, die, core, grid_size, "vertical", stage + "_vertical_margin.csv"); } -std::string DensityEval::evalAllMargin(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size) +std::string DensityEval::evalAllMargin(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size, std::string stage) { - return evalMargin(cells, die, core, grid_size, "union", "union_margin.csv"); + return evalMargin(cells, die, core, grid_size, "union", stage + "_union_margin.csv"); } std::string DensityEval::evalDensity(DensityCells cells, DensityRegion region, int32_t grid_size, std::string cell_type, @@ -147,7 +148,14 @@ std::string DensityEval::evalDensity(DensityCells cells, DensityRegion region, i } } - std::string output_path = createDirPath("/density_map") + "/" + output_filename; + std::string stage; + size_t underscore_pos = output_filename.find('_'); + if (underscore_pos != std::string::npos) { + stage = output_filename.substr(0, underscore_pos); + } + + std::string save_dir = "/density_map"; + std::string output_path = createDirPath(save_dir) + "/" + output_filename; std::ofstream csv_file(output_path); for (size_t row_index = density_grid.size(); row_index-- > 0;) { @@ -227,11 +235,18 @@ std::string DensityEval::evalPinDensity(DensityPins pins, DensityRegion region, } } + std::string stage; + size_t underscore_pos = output_filename.find('_'); + if (underscore_pos != std::string::npos) { + stage = output_filename.substr(0, underscore_pos); + } + + std::string save_dir="/density_map"; std::string output_path; if (neighbor) { - output_path = createDirPath("/density_map") + "/" + "neighbor_" + output_filename; + output_path = createDirPath(save_dir) + "/" + "neighbor_" + output_filename; } else { - output_path = createDirPath("/density_map") + "/" + output_filename; + output_path = createDirPath(save_dir) + "/" + output_filename; } std::ofstream csv_file(output_path); @@ -280,6 +295,13 @@ std::string DensityEval::evalNetDensity(DensityNets nets, DensityRegion region, } } + std::string stage; + size_t underscore_pos = output_filename.find('_'); + if (underscore_pos != std::string::npos) { + stage = output_filename.substr(0, underscore_pos); + } + + std::string save_dir="/density_map"; std::string output_path; if (neighbor) { const std::vector> kernel = {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}; @@ -301,7 +323,7 @@ std::string DensityEval::evalNetDensity(DensityNets nets, DensityRegion region, neighbor_net_count[row][col] = sum; } } - output_path = createDirPath("/density_map") + "/" + "neighbor_" + output_filename; + output_path = createDirPath(save_dir) + "/" + "neighbor_" + output_filename; std::ofstream csv_file(output_path); for (int32_t row = grid_rows - 1; row >= 0; --row) { for (int32_t col = 0; col < grid_cols; ++col) { @@ -316,7 +338,7 @@ std::string DensityEval::evalNetDensity(DensityNets nets, DensityRegion region, } else { - output_path = createDirPath("/density_map") + "/" + output_filename; + output_path = createDirPath(save_dir) + "/" + output_filename; std::ofstream csv_file(output_path); for (int32_t row = grid_rows - 1; row >= 0; --row) { for (int32_t col = 0; col < grid_cols; ++col) { @@ -412,7 +434,14 @@ std::string DensityEval::evalMargin(DensityCells cells, DensityRegion die, Densi } } - std::string output_path = createDirPath("margin_map") + "/" + output_filename; + std::string stage; + size_t underscore_pos = output_filename.find('_'); + if (underscore_pos != std::string::npos) { + stage = output_filename.substr(0, underscore_pos); + } + + std::string save_dir="/margin_map"; + std::string output_path = createDirPath(save_dir) + "/" + output_filename; std::ofstream csv_file(output_path); int32_t grid_cols = (die.ux - die.lx + grid_size - 1) / grid_size; @@ -516,4 +545,476 @@ std::vector DensityEval::initMarginGrid(DensityRegion die, int32_t g return margin_grids; } +std::map DensityEval::patchCellDensity(DensityCells cells, std::map, std::pair>> patch_coords) +{ + std::map patch_cell_density; + DensityGridIndex index; + index.grid_size_x = EVAL_INIT_IDB_INST->getDieWidth() / 100 ; + index.grid_size_y = EVAL_INIT_IDB_INST->getDieHeight() / 100; + // 构建单元格网格索引 + for (auto& cell : cells) { + int min_grid_x = cell.lx / index.grid_size_x; + int max_grid_x = (cell.lx + cell.width) / index.grid_size_x; + int min_grid_y = cell.ly / index.grid_size_y; + int max_grid_y = (cell.ly + cell.height) / index.grid_size_y; + + for (int x = min_grid_x; x <= max_grid_x; ++x) { + for (int y = min_grid_y; y <= max_grid_y; ++y) { + index.cell_grid[{x, y}].push_back(cell); + } + } + } + + for (const auto& [patch_id, coord] : patch_coords) { + double density = 0.0; + auto [l_range, u_range] = coord; + + // 提取当前 patch 的物理边界 + const int patch_lx = l_range.first; + const int patch_ly = l_range.second; + const int patch_ux = u_range.first; + const int patch_uy = u_range.second; + + // 计算 patch 面积(保持与 pin 密度相同的左闭右开区间) + const int patch_width = patch_ux - patch_lx; + const int patch_height = patch_uy - patch_ly; + const int patch_area = patch_width * patch_height; + + // 计算 patch 覆盖的网格范围 + int min_grid_x = patch_lx / index.grid_size_x; + int max_grid_x = patch_ux / index.grid_size_x; + int min_grid_y = patch_ly / index.grid_size_y; + int max_grid_y = patch_uy / index.grid_size_y; + + std::unordered_set processed_cells; // 记录已处理的 cell ID, 避免重复多次处理同一cell + + for (int x = min_grid_x; x <= max_grid_x; ++x) { + for (int y = min_grid_y; y <= max_grid_y; ++y) { + auto it = index.cell_grid.find({x, y}); + if (it == index.cell_grid.end()) continue; + + for (const auto& cell : it->second) { + if (processed_cells.count(cell.id)) continue; + processed_cells.insert(cell.id); + // 计算重叠面积 + const int overlap_lx = std::max(cell.lx, patch_lx); + const int overlap_ly = std::max(cell.ly, patch_ly); + const int overlap_ux = std::min(cell.lx + cell.width, patch_ux); + const int overlap_uy = std::min(cell.ly + cell.height, patch_uy); + + // 有效重叠面积计算 + const int overlap_width = std::max(0, overlap_ux - overlap_lx); + const int overlap_height = std::max(0, overlap_uy - overlap_ly); + const int overlap_area = overlap_width * overlap_height; + + // 累加密度贡献(当且仅当有重叠时) + if (overlap_area > 0) { + density += static_cast(overlap_area) / patch_area; + } + + } + } + } + + patch_cell_density[patch_id] = density; + } + + return patch_cell_density; +} + + +std::map DensityEval::patchPinDensity(DensityPins pins, std::map, std::pair>> patch_coords) +{ + std::map patch_pin_density; + + // 构建 pin 网格索引 + DensityGridIndex index; + index.grid_size_x = EVAL_INIT_IDB_INST->getDieWidth() / 100 ; + index.grid_size_y = EVAL_INIT_IDB_INST->getDieHeight() / 100; + + for (const auto& pin : pins) { + int grid_x = pin.lx / index.grid_size_x; + int grid_y = pin.ly / index.grid_size_y; + index.pin_grid[{grid_x, grid_y}].push_back(pin); + } + + for (const auto& [patch_id, coord] : patch_coords) { + auto [l_range, u_range] = coord; + const int patch_lx = l_range.first; + const int patch_ly = l_range.second; + const int patch_ux = u_range.first; + const int patch_uy = u_range.second; + + int pin_count = 0; + + // 计算覆盖网格范围 + int min_grid_x = patch_lx / index.grid_size_x; + int max_grid_x = patch_ux / index.grid_size_x; + int min_grid_y = patch_ly / index.grid_size_y; + int max_grid_y = patch_uy / index.grid_size_y; + + for (int x = min_grid_x; x <= max_grid_x; ++x) { + for (int y = min_grid_y; y <= max_grid_y; ++y) { + auto it = index.pin_grid.find({x, y}); + if (it == index.pin_grid.end()) continue; + + for (const auto& pin : it->second) { + if (pin.lx >= patch_lx && pin.ly >= patch_ly && + pin.lx <= patch_ux && pin.ly <= patch_uy) + { + ++pin_count; + } + } + } + } + patch_pin_density[patch_id] = pin_count; + } + return patch_pin_density; +} + +std::map DensityEval::patchNetDensity(DensityNets nets, std::map, std::pair>> patch_coords) +{ + std::map patch_net_density; + DensityGridIndex index; + index.grid_size_x = EVAL_INIT_IDB_INST->getDieWidth() / 100 ; + index.grid_size_y = EVAL_INIT_IDB_INST->getDieHeight() / 100; + + // 构建线网网格索引 + for (const auto& net : nets) { + int min_grid_x = net.lx / index.grid_size_x; + int max_grid_x = net.ux / index.grid_size_x; + int min_grid_y = net.ly / index.grid_size_y; + int max_grid_y = net.uy / index.grid_size_y; + + for (int x = min_grid_x; x <= max_grid_x; ++x) { + for (int y = min_grid_y; y <= max_grid_y; ++y) { + index.net_grid[{x, y}].push_back(net); + } + } + } + + for (const auto& [patch_id, coord] : patch_coords) { + double density = 0.0; + auto [l_range, u_range] = coord; + + // 提取当前 patch 的物理边界 + const int patch_lx = l_range.first; + const int patch_ly = l_range.second; + const int patch_ux = u_range.first; + const int patch_uy = u_range.second; + + // 计算 patch 面积(保持与 pin 密度相同的左闭右开区间) + const int patch_width = patch_ux - patch_lx; + const int patch_height = patch_uy - patch_ly; + const int patch_area = patch_width * patch_height; + + // 计算 patch 覆盖的网格范围 + int min_grid_x = patch_lx / index.grid_size_x; + int max_grid_x = patch_ux / index.grid_size_x; + int min_grid_y = patch_ly / index.grid_size_y; + int max_grid_y = patch_uy / index.grid_size_y; + + std::unordered_set processed_nets; // 记录已处理的 net ID, 避免重复多次处理同一 net + + for (int x = min_grid_x; x <= max_grid_x; ++x) { + for (int y = min_grid_y; y <= max_grid_y; ++y) { + auto it = index.net_grid.find({x, y}); + if (it == index.net_grid.end()) continue; + + for (const auto& net : it->second) { + if (processed_nets.count(net.id)) continue; + processed_nets.insert(net.id); + // 计算重叠面积 + const int overlap_lx = std::max(net.lx, patch_lx); + const int overlap_ly = std::max(net.ly, patch_ly); + const int overlap_ux = std::min(net.ux, patch_ux); + const int overlap_uy = std::min(net.uy, patch_uy); + + // 有效重叠面积计算 + const int overlap_width = std::max(0, overlap_ux - overlap_lx); + const int overlap_height = std::max(0, overlap_uy - overlap_ly); + const int overlap_area = overlap_width * overlap_height; + + // 累加密度贡献(当且仅当有重叠时) + if (overlap_area > 0) { + density += static_cast(overlap_area) / patch_area; + } + + } + } + } + + patch_net_density[patch_id] = density; + } + + return patch_net_density; +} + +std::map DensityEval::patchMacroMargin(DensityCells cells, DensityRegion core, std::map, std::pair>> patch_coords) +{ + std::map patch_macro_margin; + + std::vector macros; + for (const auto& cell : cells) { + if (cell.type == "macro") { + macros.push_back(cell); + } + } + + for (const auto& [patch_id, coord] : patch_coords) { + auto [l_range, u_range] = coord; + + // 提取当前 patch 的物理边界 + const int patch_lx = l_range.first; + const int patch_ly = l_range.second; + const int patch_ux = u_range.first; + const int patch_uy = u_range.second; + // 计算核心区域的边界 + int32_t h_right = core.ux; + int32_t h_left = core.lx; + int32_t v_up = core.uy; + int32_t v_down = core.ly; + + if (patch_ux <= h_left || patch_lx >= h_right || patch_uy <= v_down || patch_ly >= v_up) { + patch_macro_margin[patch_id] = 0; // 确保所有情况都有赋值 + continue; + } + + const int patch_width = patch_ux - patch_lx; + const int patch_height = patch_uy - patch_ly; + const int patch_area = patch_width * patch_height; + + bool overlap = false; + int overlap_area = 0; + int margin = 0; + + for (size_t j = 0; j < macros.size(); ++j) { + int32_t rect_lx = std::max(patch_lx, macros[j].lx); + int32_t rect_ly = std::max(patch_ly, macros[j].ly); + int32_t rect_ux = std::min(patch_ux, macros[j].lx + macros[j].width); + int32_t rect_uy = std::min(patch_uy, macros[j].ly + macros[j].height); + if (rect_lx < rect_ux && rect_ly < rect_uy) { + overlap_area += (std::min(patch_ux, macros[j].lx + macros[j].width) - std::max(patch_lx, macros[j].lx)) + * (std::min(patch_uy, macros[j].ly + macros[j].height) - std::max(patch_ly, macros[j].ly)); + } + if (overlap_area > 0.5 * patch_area) { + overlap = true; + break; + } + } + + if (!overlap) { + for (size_t j = 0; j < macros.size(); ++j) { + int32_t macro_middle_x = macros[j].lx + macros[j].width * 0.5; + int32_t macro_middle_y = macros[j].ly + macros[j].height * 0.5; + int32_t grid_middle_x = (patch_lx + patch_ux) * 0.5; + int32_t grid_middle_y = (patch_ly + patch_uy) * 0.5; + if (grid_middle_y >= macros[j].ly && grid_middle_y <= macros[j].ly + macros[j].height) { + if (macro_middle_x > grid_middle_x) { + h_right = std::min(h_right, macros[j].lx); + } else { + h_left = std::max(h_left, macros[j].lx + macros[j].width); + } + } + if (grid_middle_x >= macros[j].lx && grid_middle_x <= macros[j].lx + macros[j].width) { + if (macro_middle_y > grid_middle_y) { + v_up = std::min(v_up, macros[j].ly); + } else { + v_down = std::max(v_down, macros[j].ly + macros[j].height); + } + } + } + margin = h_right - h_left + v_up - v_down; + } + + patch_macro_margin[patch_id] = margin; + } + return patch_macro_margin; +} + +DensityValue DensityEval::calCellDensity(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) +{ + DensityRegion region = getDensityRegion(); + DensityCells cells = getDensityCells(); + + std::vector> density_grid(bin_cnt_y, std::vector(bin_cnt_x, 0.0)); + + double grid_size_x = static_cast(region.ux - region.lx) / bin_cnt_x; + double grid_size_y = static_cast(region.uy - region.ly) / bin_cnt_y; + + for (const auto& cell : cells) { + int32_t start_row = std::max(0, static_cast((cell.ly - region.ly) / grid_size_y)); + int32_t end_row = std::min(bin_cnt_y - 1, static_cast((cell.ly + cell.height - region.ly) / grid_size_y)); + + int32_t start_col = std::max(0, static_cast((cell.lx - region.lx) / grid_size_x)); + int32_t end_col = std::min(bin_cnt_x - 1, static_cast((cell.lx + cell.width - region.lx) / grid_size_x)); + + for (int32_t row = start_row; row <= end_row; ++row) { + for (int32_t col = start_col; col <= end_col; ++col) { + double grid_lx = region.lx + col * grid_size_x; + double grid_ly = region.ly + row * grid_size_y; + double grid_ux = std::min(region.lx + (col + 1) * grid_size_x, static_cast(region.ux)); + double grid_uy = std::min(region.ly + (row + 1) * grid_size_y, static_cast(region.uy)); + + double overlap_lx = std::max(static_cast(cell.lx), grid_lx); + double overlap_ly = std::max(static_cast(cell.ly), grid_ly); + double overlap_ux = std::min(static_cast(cell.lx + cell.width), grid_ux); + double overlap_uy = std::min(static_cast(cell.ly + cell.height), grid_uy); + + double overlap_area = std::max(0.0, overlap_ux - overlap_lx) * std::max(0.0, overlap_uy - overlap_ly); + double grid_area = (grid_ux - grid_lx) * (grid_uy - grid_ly); + + density_grid[row][col] += overlap_area / grid_area; + } + } + } + + if (!save_path.empty()) { + std::ofstream csv_file(save_path); + if (csv_file.is_open()) { + for (size_t row_index = density_grid.size(); row_index-- > 0;) { + const auto& row = density_grid[row_index]; + for (size_t i = 0; i < row.size(); ++i) { + csv_file << std::fixed << std::setprecision(6) << row[i]; + if (i < row.size() - 1) + csv_file << ","; + } + csv_file << "\n"; + } + csv_file.close(); + } + } + + double total_density = 0.0; + double max_density = 0.0; + + for (const auto& row : density_grid) { + for (double density : row) { + total_density += density; + max_density = std::max(max_density, density); + } + } + + DensityValue result; + result.max_density = max_density; + result.avg_density = total_density / (bin_cnt_x * bin_cnt_y); + + return result; +} + +DensityValue DensityEval::calPinDensity(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) +{ + DensityRegion region = getDensityRegion(); + DensityPins pins = getDensityPins(); + + std::vector> density_grid(bin_cnt_y, std::vector(bin_cnt_x, 0.0)); + + double grid_size_x = static_cast(region.ux - region.lx) / bin_cnt_x; + double grid_size_y = static_cast(region.uy - region.ly) / bin_cnt_y; + + for (const auto& pin : pins) { + int32_t col = static_cast((pin.lx - region.lx) / grid_size_x); + int32_t row = static_cast((pin.ly - region.ly) / grid_size_y); + + if (col >= 0 && col < bin_cnt_x && row >= 0 && row < bin_cnt_y) { + density_grid[row][col] += 1.0; + } + } + + if (!save_path.empty()) { + std::ofstream csv_file(save_path); + if (csv_file.is_open()) { + for (size_t row_index = density_grid.size(); row_index-- > 0;) { + const auto& row = density_grid[row_index]; + for (size_t i = 0; i < row.size(); ++i) { + csv_file << std::fixed << std::setprecision(6) << row[i]; + if (i < row.size() - 1) + csv_file << ","; + } + csv_file << "\n"; + } + csv_file.close(); + } + } + + double total_density = 0.0; + double max_density = 0.0; + + for (const auto& row : density_grid) { + for (double density : row) { + total_density += density; + max_density = std::max(max_density, density); + } + } + + DensityValue result; + result.max_density = max_density; + result.avg_density = total_density / (bin_cnt_x * bin_cnt_y); + + return result; +} + +DensityValue DensityEval::calNetDensity(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) +{ + DensityRegion region = getDensityRegion(); + DensityNets nets = getDensityNets(); + + std::vector> density_grid(bin_cnt_y, std::vector(bin_cnt_x, 0.0)); + + double grid_size_x = static_cast(region.ux - region.lx) / bin_cnt_x; + double grid_size_y = static_cast(region.uy - region.ly) / bin_cnt_y; + + for (const auto& net : nets) { + int32_t start_col = std::max(0, static_cast((net.lx - region.lx) / grid_size_x)); + int32_t end_col = std::min(bin_cnt_x - 1, static_cast((net.ux - region.lx) / grid_size_x)); + int32_t start_row = std::max(0, static_cast((net.ly - region.ly) / grid_size_y)); + int32_t end_row = std::min(bin_cnt_y - 1, static_cast((net.uy - region.ly) / grid_size_y)); + + bool is_local = (start_col == end_col) && (start_row == end_row); + + if (is_local) { + density_grid[start_row][start_col] += 1.0; + } else { + for (int32_t row = start_row; row <= end_row; ++row) { + for (int32_t col = start_col; col <= end_col; ++col) { + density_grid[row][col] += 1.0; + } + } + } + } + + if (!save_path.empty()) { + std::ofstream csv_file(save_path); + if (csv_file.is_open()) { + for (size_t row_index = density_grid.size(); row_index-- > 0;) { + const auto& row = density_grid[row_index]; + for (size_t i = 0; i < row.size(); ++i) { + csv_file << std::fixed << std::setprecision(6) << row[i]; + if (i < row.size() - 1) + csv_file << ","; + } + csv_file << "\n"; + } + csv_file.close(); + } + } + + double total_density = 0.0; + double max_density = 0.0; + + for (const auto& row : density_grid) { + for (double density : row) { + total_density += density; + max_density = std::max(max_density, density); + } + } + + DensityValue result; + result.max_density = max_density; + result.avg_density = total_density / (bin_cnt_x * bin_cnt_y); + + return result; +} + + } // namespace ieval diff --git a/src/evaluation/src/module/density/density_eval.h b/src/evaluation/src/module/density/density_eval.h index 3a5267a03459452ca0a7301b51904f1ddbbe8128..b633554239416598649b8473eb59012753196f16 100644 --- a/src/evaluation/src/module/density/density_eval.h +++ b/src/evaluation/src/module/density/density_eval.h @@ -8,6 +8,10 @@ #pragma once #include "density_db.h" +#include +#include +#include +#include namespace ieval { struct MarginGrid @@ -19,6 +23,25 @@ struct MarginGrid int32_t margin; }; +// 辅助哈希函数 +struct DensityPairHash { + template + std::size_t operator () (const std::pair &p) const { + auto h1 = std::hash{}(p.first); + auto h2 = std::hash{}(p.second); + return h1 ^ (h2 << 1); + } +}; + +// 网格索引结构体 +struct DensityGridIndex { + int grid_size_x = 2000; // 默认x方向网格大小 + int grid_size_y = 2000; // 默认y方向网格大小 + std::unordered_map, DensityCells, DensityPairHash> cell_grid; + std::unordered_map, DensityPins, DensityPairHash> pin_grid; + std::unordered_map, DensityNets, DensityPairHash> net_grid; +}; + class DensityEval { public: @@ -39,9 +62,9 @@ class DensityEval std::string evalGlobalNetDensity(DensityNets nets, DensityRegion region, int32_t grid_size, std::string stage, bool neighbor); std::string evalAllNetDensity(DensityNets nets, DensityRegion region, int32_t grid_size, std::string stage, bool neighbor); - std::string evalHorizonMargin(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size); - std::string evalVerticalMargin(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size); - std::string evalAllMargin(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size); + std::string evalHorizonMargin(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size, std::string stage); + std::string evalVerticalMargin(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size, std::string stage); + std::string evalAllMargin(DensityCells cells, DensityRegion die, DensityRegion core, int32_t grid_size, std::string stage); void initIDB(); void destroyIDB(); @@ -57,6 +80,15 @@ class DensityEval int32_t getRowHeight(); + std::map patchPinDensity(DensityPins pins, std::map, std::pair>> patch_coords); + std::map patchCellDensity(DensityCells cells, std::map, std::pair>> patch_coords); + std::map patchNetDensity(DensityNets nets, std::map, std::pair>> patch_coords); + std::map patchMacroMargin(DensityCells cells, DensityRegion core, std::map, std::pair>> patch_coords); + + DensityValue calCellDensity(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); + DensityValue calPinDensity(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); + DensityValue calNetDensity(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); + private: static DensityEval* _density_eval; diff --git a/src/evaluation/src/module/timing/timing_eval.cc b/src/evaluation/src/module/timing/timing_eval.cc index 01111e72370f4c1ae2c9c8a6a7bacb9c99d544cb..2c359d5a7c18ac4058a795305611fbe726f42f25 100644 --- a/src/evaluation/src/module/timing/timing_eval.cc +++ b/src/evaluation/src/module/timing/timing_eval.cc @@ -26,11 +26,32 @@ void TimingEval::runSTA() EVAL_INIT_STA_INST->runSTA(); } +void TimingEval::runVecSTA(ivec::VecLayout* vec_layout) +{ + EVAL_INIT_STA_INST->runVecSTA(vec_layout, "./"); +} + void TimingEval::evalTiming(const std::string& routing_type, const bool& rt_done) { EVAL_INIT_STA_INST->evalTiming(routing_type, rt_done); } +// for vectorization(to weiguo) +TimingWireGraph* TimingEval::getTimingWireGraph() +{ + auto timing_wire_graph = EVAL_INIT_STA_INST->getTimingWireGraph(); + auto timing_wire_graph_ptr = new TimingWireGraph(std::move(timing_wire_graph)); + return timing_wire_graph_ptr; +} + +// for vectorization(to wangrui) +TimingInstanceGraph* TimingEval::getTimingInstanceGraph() +{ + auto timing_instance_graph = EVAL_INIT_STA_INST->getTimingInstanceGraph(); + auto timing_instance_graph_ptr = new TimingInstanceGraph(std::move(timing_instance_graph)); + return timing_instance_graph_ptr; +} + void TimingEval::destroyInst() { delete _timing_eval; @@ -121,4 +142,19 @@ bool TimingEval::isClockNet(const std::string& net_name) const return EVAL_INIT_STA_INST->isClockNet(net_name); } +std::map TimingEval::patchTimingMap(std::map, std::pair>>& patch) +{ + return EVAL_INIT_STA_INST->patchTimingMap(patch); +} + +std::map TimingEval::patchPowerMap(std::map, std::pair>>& patch) +{ + return EVAL_INIT_STA_INST->patchPowerMap(patch); +} + +std::map TimingEval::patchIRDropMap(std::map, std::pair>>& patch) +{ + return EVAL_INIT_STA_INST->patchIRDropMap(patch); +} + } // namespace ieval \ No newline at end of file diff --git a/src/evaluation/src/module/timing/timing_eval.hh b/src/evaluation/src/module/timing/timing_eval.hh index 7847afccb1574a5d16fdce22c2f1668702cebac1..8df4b9608b1edc8f5cf6e827dce3f21e4f43a2a4 100644 --- a/src/evaluation/src/module/timing/timing_eval.hh +++ b/src/evaluation/src/module/timing/timing_eval.hh @@ -17,8 +17,16 @@ namespace ista { enum class AnalysisMode; } + +namespace ivec { +class VecLayout; +} + namespace ieval { +class TimingWireGraph; +class TimingInstanceGraph; + class TimingEval { public: @@ -27,7 +35,10 @@ class TimingEval static TimingEval* getInst(); void runSTA(); + void runVecSTA(ivec::VecLayout* vec_layout); void evalTiming(const std::string& routing_type, const bool& rt_done = false); + TimingWireGraph* getTimingWireGraph(); + TimingInstanceGraph* getTimingInstanceGraph(); static void destroyInst(); @@ -50,6 +61,10 @@ class TimingEval bool isClockNet(const std::string& net_name) const; + std::map patchTimingMap(std::map, std::pair>>& patch); + std::map patchPowerMap(std::map, std::pair>>& patch); + std::map patchIRDropMap(std::map, std::pair>>& patch); + private: static TimingEval* _timing_eval; }; diff --git a/src/evaluation/src/module/wirelength/wirelength_eval.cpp b/src/evaluation/src/module/wirelength/wirelength_eval.cpp index 17ed0b72e9b8f8a4cfba17cdc3bb5bd0cf9e8929..c42e396907a9449669607bead458009b8b8fc589 100644 --- a/src/evaluation/src/module/wirelength/wirelength_eval.cpp +++ b/src/evaluation/src/module/wirelength/wirelength_eval.cpp @@ -437,6 +437,14 @@ void WirelengthEval::evalNetInfo() } } +void WirelengthEval::evalNetFlute() +{ + auto name_pointset = getNamePointSet(); + for (const auto& [net_name, point_set] : name_pointset) { + _name_flute[net_name] = evalNetFLUTE(point_set); + } +} + int32_t WirelengthEval::findHPWL(std::string net_name) { auto it = _name_hpwl.find(net_name); diff --git a/src/evaluation/src/module/wirelength/wirelength_eval.h b/src/evaluation/src/module/wirelength/wirelength_eval.h index d1adec45814de76b7b7674db0772f84e283a4a08..422a277febdfee3d4ae285a06bf983dcf5b852ac 100644 --- a/src/evaluation/src/module/wirelength/wirelength_eval.h +++ b/src/evaluation/src/module/wirelength/wirelength_eval.h @@ -58,6 +58,7 @@ class WirelengthEval void destroyFlute(); void evalNetInfo(); + void evalNetFlute(); int32_t findHPWL(std::string net_name); int32_t findFLUTE(std::string net_name); int32_t findGRWL(std::string net_name); diff --git a/src/evaluation/src/util/CMakeLists.txt b/src/evaluation/src/util/CMakeLists.txt index 4793bf472b912940ea7c77171bd51ec3693e973c..3ec9e6d22219e41a397463c8e3431b29710c9b42 100644 --- a/src/evaluation/src/util/CMakeLists.txt +++ b/src/evaluation/src/util/CMakeLists.txt @@ -1,5 +1,4 @@ -set(CMAKE_BUILD_TYPE "Release") -# set(CMAKE_BUILD_TYPE "Debug") +# set(CMAKE_BUILD_TYPE "Release") # general ops add_library(eval_util_general_ops @@ -57,10 +56,12 @@ target_link_libraries(eval_util_init_ista PRIVATE ieda_feature idm + ivec_api irt_interface ista-engine power salt + ivec_layout_db ) target_include_directories(eval_util_init_ista diff --git a/src/evaluation/src/util/general_ops.cpp b/src/evaluation/src/util/general_ops.cpp index f9f184912dfdba64b277e961ede1bc877151e3f7..359bb78c68df3c0f7888816dce1ed84c314780a3 100644 --- a/src/evaluation/src/util/general_ops.cpp +++ b/src/evaluation/src/util/general_ops.cpp @@ -40,24 +40,55 @@ std::string getAbsoluteFilePath(std::string filename) std::string createDirPath(std::string dir_path) { - const std::string base_path = dmInst->get_config().get_output_path(); + std::string base_path = dmInst->get_config().get_feature_path(); + if (base_path.empty()) { + base_path = dmInst->get_config().get_output_path(); + } + std::string full_path = base_path + dir_path; struct stat info; if (stat(full_path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR)) { - return full_path; + return full_path; + } + + if (createDirectoryRecursive(full_path)) { + return full_path; + } + + return ""; +} + +bool createDirectoryRecursive(const std::string& path) +{ + struct stat info; + if (stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR)) { + return true; + } + + size_t pos = path.find_last_of('/'); + if (pos != std::string::npos && pos > 0) { + std::string parent_path = path.substr(0, pos); + + if (!createDirectoryRecursive(parent_path)) { + return false; + } + } + + if (mkdir(path.c_str(), 0777) == 0) { + return true; } - if (mkdir(full_path.c_str(), 0777) == 0) { - return full_path; + if (stat(path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR)) { + return true; } - return ""; + return false; } std::string getDefaultOutputPath() { - std::string base_path = dmInst->get_config().get_output_path(); + std::string base_path = dmInst->get_config().get_feature_path(); return base_path; } diff --git a/src/evaluation/src/util/general_ops.h b/src/evaluation/src/util/general_ops.h index 74b92fdc9d6c100d46b03e33b12a943cf27f9c0a..3431089f863b7f2e696ca74bd134800e2919943c 100644 --- a/src/evaluation/src/util/general_ops.h +++ b/src/evaluation/src/util/general_ops.h @@ -14,5 +14,6 @@ namespace ieval { std::string getAbsoluteFilePath(std::string filename); std::string createDirPath(std::string dir_path); std::string getDefaultOutputPath(); +bool createDirectoryRecursive(const std::string& path); } // namespace ieval diff --git a/src/evaluation/src/util/init_idb.cpp b/src/evaluation/src/util/init_idb.cpp index e4c48f89e929f1b4f261ad352e61cb4bfc961600..b929f6b0e64f9990d69b62cec98849690a7b0e79 100644 --- a/src/evaluation/src/util/init_idb.cpp +++ b/src/evaluation/src/util/init_idb.cpp @@ -139,6 +139,16 @@ void InitIDB::initDensityDBRegion() _density_region_core.uy = core_bbox->get_high_y(); } +int32_t InitIDB::getDieHeight() +{ + return dmInst->get_idb_builder()->get_def_service()->get_layout()->get_die()->get_bounding_box()->get_height(); +} + +int32_t InitIDB::getDieWidth() +{ + return dmInst->get_idb_builder()->get_def_service()->get_layout()->get_die()->get_bounding_box()->get_width(); +} + void InitIDB::initDensityDBCells() { if (_density_db_initialized) { @@ -147,6 +157,7 @@ void InitIDB::initDensityDBCells() auto* idb_builder = dmInst->get_idb_builder(); idb::IdbDesign* idb_design = idb_builder->get_def_service()->get_design(); idb::IdbLayout* idb_layout = idb_builder->get_def_service()->get_layout(); + int id = 0; idb::IdbRect* core_bbox = idb_layout->get_core()->get_bounding_box(); int32_t core_lx = core_bbox->get_low_x(); @@ -160,6 +171,7 @@ void InitIDB::initDensityDBCells() auto cell_bbox = idb_inst->get_bounding_box(); DensityCell cell; + cell.id = id++; cell.lx = cell_bbox->get_low_x(); cell.ly = cell_bbox->get_low_y(); cell.width = cell_bbox->get_width(); @@ -195,6 +207,7 @@ void InitIDB::initDensityDBNets() } auto* idb_builder = dmInst->get_idb_builder(); idb::IdbDesign* idb_design = idb_builder->get_def_service()->get_design(); + int id = 0; for (size_t i = 0; i < idb_design->get_net_list()->get_net_list().size(); i++) { auto* idb_net = idb_design->get_net_list()->get_net_list()[i]; @@ -221,6 +234,7 @@ void InitIDB::initDensityDBNets() net.ly = min_ly; net.ux = max_ux; net.uy = max_uy; + net.id = id++; _density_nets.emplace_back(net); } } diff --git a/src/evaluation/src/util/init_idb.h b/src/evaluation/src/util/init_idb.h index a15a52e88031ea8699ccc1d75e9a3d5d735172d0..020669901df054a5dc5b6e917240490bb11c25d8 100644 --- a/src/evaluation/src/util/init_idb.h +++ b/src/evaluation/src/util/init_idb.h @@ -47,6 +47,8 @@ class InitIDB DensityCells getDensityCells() { return _density_cells; } DensityPins getDensityPins() { return _density_pins; } DensityNets getDensityNets() { return _density_nets; } + int32_t getDieHeight(); + int32_t getDieWidth(); private: static InitIDB* _init_idb; diff --git a/src/evaluation/src/util/init_sta.cc b/src/evaluation/src/util/init_sta.cc index d2f8488eecc240089d7885389f223af35faec3a8..d29863e19e81b67d449c89893a0eb37216d59fb2 100644 --- a/src/evaluation/src/util/init_sta.cc +++ b/src/evaluation/src/util/init_sta.cc @@ -1,16 +1,16 @@ // *************************************************************************************** // Copyright (c) 2023-2025 Peng Cheng Laboratory -// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences -// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of +// Sciences Copyright (c) 2023-2025 Beijing Institute of Open Source Chip // // iEDA is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. You may obtain a copy of Mulan PSL v2 at: // http://license.coscl.org.cn/MulanPSL2 // -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // // See the Mulan PSL v2 for more details. // *************************************************************************************** @@ -23,16 +23,25 @@ #include "init_sta.hh" +#include +#include + #include "RTInterface.hpp" #include "api/PowerEngine.hh" #include "api/TimingEngine.hh" #include "api/TimingIDBAdapter.hh" #include "idm.h" +#include "json/json.hpp" #include "salt/base/flute.h" #include "salt/salt.h" #include "timing_db.hh" +#include "usage/usage.hh" +#include "vec_layout.h" namespace ieval { + +using json = nlohmann::ordered_json; + #define STA_INST (ista::TimingEngine::getOrCreateTimingEngine()) #define RT_INST (irt::RTInterface::getInst()) #define PW_INST (ipower::PowerEngine::getOrCreatePowerEngine()) @@ -74,6 +83,15 @@ void InitSTA::runSTA() }); } +void InitSTA::runVecSTA(ivec::VecLayout* vec_layout, std::string work_dir) +{ + initStaEngine(); + + buildVecRCTree(vec_layout, work_dir); + + updateResult("Vectorization"); +} + void InitSTA::evalTiming(const std::string& routing_type, const bool& rt_done) { initStaEngine(); @@ -107,10 +125,9 @@ void InitSTA::leaglization(const std::vector>& pins) return; } - // find all duplicated locations, and move them to a new location, objective: no duplicated locations and minimum total movement - // x: pin->loc.x - // y: pin->loc.y - // Step 1: Group pins by their (x, y) locations + // find all duplicated locations, and move them to a new location, objective: + // no duplicated locations and minimum total movement x: pin->loc.x y: + // pin->loc.y Step 1: Group pins by their (x, y) locations std::map, std::vector>> loc_map; for (const auto& pin : pins) { std::pair coord = {pin->loc.x, pin->loc.y}; @@ -244,7 +261,8 @@ void InitSTA::callRT(const std::string& routing_type) void InitSTA::buildRCTree(const std::string& routing_type) { - LOG_FATAL_IF(routing_type != "WLM" && routing_type != "HPWL" && routing_type != "FLUTE" && routing_type != "SALT") + LOG_FATAL_IF(routing_type != "WLM" && routing_type != "HPWL" && routing_type != "FLUTE" && routing_type != "SALT" + && routing_type != "WireGraph") << "The routing type: " << routing_type << " is not supported."; auto* idb_adapter = dynamic_cast(STA_INST->get_db_adapter()); @@ -261,14 +279,15 @@ void InitSTA::buildRCTree(const std::string& routing_type) return 1.0 * dist / dbu; }; - // 2. cap and res calculation, if is clock net, return the last layer, otherwise return the first layer + // 2. cap and res calculation, if is clock net, return the last layer, + // otherwise return the first layer std::optional width = std::nullopt; auto* idb_layout = dmInst->get_idb_lef_service()->get_layout(); auto routing_layers = idb_layout->get_layers()->get_routing_layers(); auto logic_layer = routing_layers.size() >= 2 ? 2 : 1; - auto clock_layer - = routing_layers.size() >= 4 ? routing_layers.size() - 4 : logic_layer; // Hard Code, consider the clock layer is the last 3rd layer + auto clock_layer = routing_layers.size() >= 4 ? routing_layers.size() - 4 : logic_layer; // Hard Code, consider the clock layer + // is the last 3rd layer auto calc_res = [&](const bool& is_clock, const double& wirelength) { if (!is_clock) { return idb_adapter->getResistance(logic_layer, wirelength, width); @@ -283,10 +302,12 @@ void InitSTA::buildRCTree(const std::string& routing_type) }; // main flow - auto* netlist = STA_INST->get_netlist(); + auto idb_nets = idb_design->get_net_list()->get_net_list(); + auto* sta_netlist = STA_INST->get_netlist(); ista::Net* sta_net = nullptr; - FOREACH_NET(netlist, sta_net) - { + for (size_t net_id = 0; net_id < idb_nets.size(); ++net_id) { + auto* idb_net = idb_nets[net_id]; + sta_net = sta_netlist->findNet(idb_net->get_net_name().c_str()); STA_INST->resetRcTree(sta_net); // WLM if (routing_type == "WLM") { @@ -396,6 +417,154 @@ void InitSTA::buildRCTree(const std::string& routing_type) STA_INST->updateTiming(); } +void InitSTA::buildVecRCTree(ivec::VecLayout* vec_layout, std::string work_dir) +{ + // init + auto* idb = dmInst->get_idb_builder(); + auto* idb_design = idb->get_def_service()->get_design(); + + auto* idb_layout = dmInst->get_idb_layout(); + auto idb_layers = idb_layout->get_layers(); + auto layers = idb_layers->get_layers(); + auto idb_layer_1st = dmInst->get_config().get_routing_layer_1st(); + // find the first layer which get_name == "idb_layer_1st", erase the layers + // before it + auto vec_layers = layers | std::views::drop_while([&](auto layer) { return layer->get_name() != idb_layer_1st; }); + + // main flow + auto idb_nets = idb_design->get_net_list()->get_net_list(); + auto* sta_netlist = STA_INST->get_netlist(); + ista::Net* sta_net = nullptr; + auto& wire_graph = vec_layout->get_graph().get_net_map(); + for (size_t net_id = 0; net_id < idb_nets.size(); ++net_id) { + auto* idb_net = idb_nets[net_id]; + std::string the_idb_net_name = idb_net->get_net_name(); + the_idb_net_name = ieda::Str::replace(the_idb_net_name, R"(\\)", ""); + sta_net = sta_netlist->findNet(the_idb_net_name.c_str()); + + if (!wire_graph.contains(net_id)) { + continue; + } + + auto vec_net = wire_graph.at(net_id); + auto idb_inst_pins = idb_net->get_instance_pin_list()->get_pin_list(); + auto io_pins = idb_net->get_io_pins()->get_pin_list(); + auto& wires = vec_net.get_wires(); + // Check corner case + if (wires.size() == 1) { + auto& wire = wires[0]; + auto connected_nodes = wire.get_connected_nodes(); + auto* source = connected_nodes.first; + auto* target = connected_nodes.second; + if (source == target) { + continue; + } + } + auto sta_pin_ports = sta_net->get_pin_ports(); + std::unordered_map sta_pin_port_map; + std::ranges::for_each(sta_pin_ports, [&](ista::DesignObject* pin_port) { sta_pin_port_map[pin_port->getFullName()] = pin_port; }); + std::unordered_map vec_node_map; + auto make_or_find_rc_node = [&](ivec::VecNode* vec_node) { + if (vec_node_map.contains(vec_node)) { + return vec_node_map[vec_node]; + } + int pin_id = vec_node->get_node_data()->get_pin_id(); + ista::RctNode* rc_node = nullptr; + if (pin_id >= 0) { + auto pin_name_pair = vec_layout->findPinName(pin_id); + auto [inst_name, pin_type_name] = pin_name_pair; + auto pin_name = !inst_name.empty() ? (inst_name + ":" + pin_type_name) : pin_type_name; + pin_name.erase(std::remove(pin_name.begin(), pin_name.end(), '\\'), pin_name.end()); + auto* sta_pin_port = sta_pin_port_map[pin_name]; + rc_node = STA_INST->makeOrFindRCTreeNode(sta_pin_port); + } else { + // steiner node + rc_node = STA_INST->makeOrFindRCTreeNode(sta_net, vec_node->get_node_id()); + } + vec_node_map[vec_node] = rc_node; + return rc_node; + }; + auto calc_res_cap = [&](ivec::VecNetWire& wire) { + auto connected_nodes = wire.get_connected_nodes(); + auto* source = connected_nodes.first; + auto* target = connected_nodes.second; + auto source_layer = source->get_layer_id(); + auto target_layer = target->get_layer_id(); + if (source_layer != target_layer) { + // is via + return std::make_pair(0.0, 0.0); + } + auto& paths = wire.get_paths(); + int wirelength = 0; + std::ranges::for_each(paths, [&](auto& path) { + auto x1 = path.first->get_x(); + auto y1 = path.first->get_y(); + auto x2 = path.second->get_x(); + auto y2 = path.second->get_y(); + wirelength += std::abs(x1 - x2) + std::abs(y1 - y2); + }); + + auto* routing_layer = dynamic_cast(vec_layers[source_layer]); + + auto dbu = idb_layout->get_units()->get_micron_dbu(); + auto segment_width = ((double) routing_layer->get_width()) / dbu; + + double wirelength_um = ((double) wirelength) / dbu; + + auto lef_resistance = routing_layer->get_resistance(); + auto lef_capacitance = routing_layer->get_capacitance(); + auto lef_edge_capacitance = routing_layer->get_edge_capacitance(); + + auto res = lef_resistance * wirelength_um / segment_width; + auto cap = (lef_capacitance * wirelength_um * segment_width) + (lef_edge_capacitance * 2 * (wirelength_um + segment_width)); + + return std::make_pair(res, cap); + }; + std::ranges::for_each(wires, [&](ivec::VecNetWire& wire) { + auto connected_nodes = wire.get_connected_nodes(); + auto* source = connected_nodes.first; + auto* target = connected_nodes.second; + + auto* front_node = make_or_find_rc_node(source); + auto* back_node = make_or_find_rc_node(target); + + auto [res, cap] = calc_res_cap(wire); + STA_INST->makeResistor(sta_net, front_node, back_node, res); + STA_INST->incrCap(front_node, cap / 2, true); + STA_INST->incrCap(back_node, cap / 2, true); + }); + + std::vector pin_names; + std::ranges::for_each(wires, [&pin_names, vec_layout](ivec::VecNetWire& wire) { + auto connected_nodes = wire.get_connected_nodes(); + auto* source = connected_nodes.first; + auto* target = connected_nodes.second; + + for (auto* connected_node : {source, target}) { + int pin_id = connected_node->get_node_data()->get_pin_id(); + + if (pin_id != -1) { + auto [inst_name, pin_type_name] = vec_layout->findPinName(pin_id); + auto pin_name = !inst_name.empty() ? (inst_name + ":" + pin_type_name) : pin_type_name; + + pin_names.push_back(pin_name); + } + } + }); + + LOG_INFO << "Net " << idb_net->get_net_name() << " has " << pin_names.size() << " pins"; + + // update rc tree + STA_INST->updateRCTreeInfo(sta_net); + } + STA_INST->updateTiming(); + STA_INST->get_ista()->reportUsedLibs(); + + std::string path_dir = work_dir; + STA_INST->set_design_work_space(path_dir.c_str()); + STA_INST->reportWirePaths(10000); +} + void InitSTA::initPowerEngine() { if (!PW_INST->isBuildGraph()) { @@ -551,6 +720,156 @@ double InitSTA::reportTNS(const char* clock_name, ista::AnalysisMode mode) return STA_INST->getTNS(clock_name, mode); } +double InitSTA::getNetResistance(const std::string& net_name) const +{ + auto netlist = STA_INST->get_netlist(); + ista::Net* ista_net = netlist->findNet(net_name.c_str()); + auto* rc_net = STA_INST->get_ista()->getRcNet(ista_net); + + if (rc_net && ista_net->getDriver()) { + double resistance = rc_net->getNetResistance(); + return resistance; + } + + return 0.0; +} +double InitSTA::getNetCapacitance(const std::string& net_name) const +{ + auto netlist = STA_INST->get_netlist(); + ista::Net* ista_net = netlist->findNet(net_name.c_str()); + auto* rc_net = STA_INST->get_ista()->getRcNet(ista_net); + + if (rc_net && ista_net->getDriver()) { + double load = rc_net->load(); + return load; + } + + return 0.0; +} + +double InitSTA::getNetSlew(const std::string& net_name) const +{ + auto netlist = STA_INST->get_netlist(); + ista::Net* ista_net = netlist->findNet(net_name.c_str()); + auto* rc_net = STA_INST->get_ista()->getRcNet(ista_net); + + if (!ista_net->getDriver()) { + return 0.0; + } + + if (!rc_net) { + return 0.0; + } + + double driver_slew = 0.0; + auto* driver = rc_net->get_net()->getDriver(); + if (driver && driver->isPin()) { + driver_slew = STA_INST->getSlew(driver->getFullName().c_str(), ista::AnalysisMode::kMax, ista::TransType::kRise); + } + // get driver slew for net slew. + auto loads = ista_net->getLoads(); + + double sum_load_slew = 0.0; + for (auto* load : loads) { + std::string load_name = load->getFullName(); + sum_load_slew += rc_net->slew(load_name.c_str(), driver_slew, ista::AnalysisMode::kMax, ista::TransType::kRise).value_or(0.0); + } + double net_avg_slew = (sum_load_slew / loads.size()) - driver_slew; + return net_avg_slew; +} + +std::map InitSTA::getAllNodesSlew(const std::string& net_name) const +{ + auto netlist = STA_INST->get_netlist(); + ista::Net* ista_net = netlist->findNet(net_name.c_str()); + auto* rc_net = STA_INST->get_ista()->getRcNet(ista_net); + + double driver_slew = 0.0; + auto* driver = rc_net->get_net()->getDriver(); + if (driver && driver->isPin()) { + driver_slew = STA_INST->getSlew(driver->getFullName().c_str(), ista::AnalysisMode::kMax, ista::TransType::kRise); + } + + std::map all_node_slews; + + if (rc_net->rct()) { + all_node_slews = rc_net->getAllNodeSlew(driver_slew, ista::AnalysisMode::kMax, ista::TransType::kRise); + } + + return all_node_slews; +} + +double InitSTA::getNetDelay(const std::string& net_name) const +{ + auto netlist = STA_INST->get_netlist(); + ista::Net* ista_net = netlist->findNet(net_name.c_str()); + auto* rc_net = STA_INST->get_ista()->getRcNet(ista_net); + + // get load average delay for net delay. + auto loads = ista_net->getLoads(); + + double sum_load_delay = 0.0; + for (auto* load : loads) { + std::string load_name = load->getFullName(); + sum_load_delay += rc_net->delay(load_name.c_str()).value_or(0.0); + } + + double net_avg_delay = sum_load_delay / loads.size(); + return net_avg_delay; +} + +std::pair InitSTA::getNetToggleAndVoltage(const std::string& net_name) const +{ + return PW_INST->get_power()->getNetToggleAndVoltageData(net_name.c_str()); +} + +double InitSTA::getNetPower(const std::string& net_name) const +{ + // get net power from updated results. + auto& nets_power = _net_power.begin()->second; + if (nets_power.contains(net_name)) { + double net_power = nets_power.at(net_name); + return net_power; + } else { + return 0.0; + } +} + +double InitSTA::getWireResistance(const std::string& net_name, const std::string& wire_node_name) const +{ + auto netlist = STA_INST->get_netlist(); + ista::Net* ista_net = netlist->findNet(net_name.c_str()); + auto* rc_net = STA_INST->get_ista()->getRcNet(ista_net); + + LOG_FATAL_IF(!rc_net) << "net " << net_name << " not found rc net."; + + double resistance = rc_net->getNodeResistance(wire_node_name.c_str()); + return resistance; +} + +double InitSTA::getWireCapacitance(const std::string& net_name, const std::string& wire_node_name) const +{ + auto netlist = STA_INST->get_netlist(); + ista::Net* ista_net = netlist->findNet(net_name.c_str()); + auto* rc_net = STA_INST->get_ista()->getRcNet(ista_net); + + LOG_FATAL_IF(!rc_net) << "net " << net_name << " not found rc net."; + + double load = rc_net->getNodeLoad(wire_node_name.c_str()); + return load; +} + +double InitSTA::getWireDelay(const std::string& net_name, const std::string& wire_node_name) const +{ + auto netlist = STA_INST->get_netlist(); + ista::Net* ista_net = netlist->findNet(net_name.c_str()); + auto* rc_net = STA_INST->get_ista()->getRcNet(ista_net); + + auto delay = rc_net->delay(wire_node_name.c_str()); + + return delay.value_or(0.0); +} + void InitSTA::updateTiming(const std::vector& timing_net_list, int32_t dbu_unit) { // get sta_netlist @@ -599,7 +918,8 @@ void InitSTA::updateTiming(const std::vector& timing_net_list, int32 int64_t wire_length = 0; wire_length = std::abs(first_pin->x - second_pin->x) + std::abs(first_pin->y - second_pin->y); - // wire_length = first_pin->get_coord().computeDist(second_pin->get_coord()); + // wire_length = + // first_pin->get_coord().computeDist(second_pin->get_coord()); std::optional width = std::nullopt; @@ -626,6 +946,389 @@ void InitSTA::updateTiming(const std::vector& timing_net_list, int32 STA_INST->reportTiming(); } +TimingWireGraph InitSTA::getTimingWireGraph() +{ + LOG_INFO << "get wire timing graph start"; + ieda::Stats stats; + + TimingWireGraph timing_wire_graph; + + /// create node in wire graph + auto create_node = [&timing_wire_graph](std::string& node_name, bool is_pin, bool is_port) -> unsigned { + auto index = timing_wire_graph.findNode(node_name); + if (!index) { + TimingWireNode the_node; + the_node._name = node_name; + the_node._is_pin = is_pin; + the_node._is_port = is_port; + + index = timing_wire_graph.addNode(the_node); + } + + return index.value(); + }; + + /// the node is StaNode + auto create_inst_node = [&create_node](auto* the_node) -> unsigned { + std::string node_name = the_node->getName(); + auto* design_obj = the_node->get_design_obj(); + bool is_pin = design_obj ? design_obj->isPin() : false; + bool is_port = design_obj ? design_obj->isPort() : false; + + auto wire_node_index = create_node(node_name, is_pin, is_port); + return wire_node_index; + }; + + /// the node is RC Node + auto create_net_node = [&create_node](auto& the_node) -> unsigned { + std::string node_name = the_node.get_name(); + bool is_pin = the_node.get_obj() ? the_node.get_obj()->isPin() : false; + bool is_port = the_node.get_obj() ? the_node.get_obj()->isPort() : false; + + auto wire_node_index = create_node(node_name, is_pin, is_port); + return wire_node_index; + }; + + auto* ista = STA_INST->get_ista(); + LOG_ERROR_IF(!ista->isBuildGraph()) << "timing graph is not build"; + + auto* the_timing_graph = &(ista->get_graph()); + ista::StaArc* the_arc; + + timing_wire_graph._edges.reserve(the_timing_graph->get_arcs().size() * 100); + timing_wire_graph._nodes.reserve(the_timing_graph->get_vertexes().size() * 10); + FOREACH_ARC(the_timing_graph, the_arc) + { + if (the_arc->isNetArc()) { + // for net arc, we need extract the wire topo. + auto* the_net_arc = dynamic_cast(the_arc); + auto* the_net = the_net_arc->get_net(); + + auto* rc_net = ista->getRcNet(the_net); + + if (rc_net) { + auto* snk_node = the_arc->get_snk(); + auto snk_node_name = snk_node->get_design_obj()->getFullName(); + + auto vertex_slew = the_arc->get_src()->getSlewNs(ista::AnalysisMode::kMax, TransType::kRise); + if (!vertex_slew) { + vertex_slew = the_arc->get_src()->getSlewNs(ista::AnalysisMode::kMax, TransType::kFall); + } + + auto wire_topo = rc_net->getWireTopo(snk_node_name.c_str()); + for (auto* wire_edge : wire_topo | std::ranges::views::reverse) { + ieda::Stats stats2; + auto& from_node = wire_edge->get_from(); + auto& to_node = wire_edge->get_to(); + + auto wire_from_node_index = create_net_node(from_node); + auto wire_to_node_index = create_net_node(to_node); + + timing_wire_graph.addEdge(wire_from_node_index, wire_to_node_index); + } + } else { + auto wire_from_node_index = create_inst_node(the_arc->get_src()); + auto wire_to_node_index = create_inst_node(the_arc->get_snk()); + + auto& inst_wire_edge = timing_wire_graph.addEdge(wire_from_node_index, wire_to_node_index); + inst_wire_edge._is_net_edge = true; + } + + } else { + auto wire_from_node_index = create_inst_node(the_arc->get_src()); + auto wire_to_node_index = create_inst_node(the_arc->get_snk()); + + auto& inst_wire_edge = timing_wire_graph.addEdge(wire_from_node_index, wire_to_node_index); + inst_wire_edge._is_net_edge = false; + } + } + + LOG_INFO << "wire timing graph nodes " << timing_wire_graph._nodes.size(); + LOG_INFO << "wire timing graph edges " << timing_wire_graph._edges.size(); + + timing_wire_graph._nodes.shrink_to_fit(); + timing_wire_graph._edges.shrink_to_fit(); + + LOG_INFO << "get wire timing graph end"; + + LOG_INFO << "get wire timing graph memory usage " << stats.memoryDelta() << " MB"; + double total_time = stats.elapsedRunTime(); + LOG_INFO << "get wire timing graph elapsed time " << total_time << " s"; + + // for debug + // SaveTimingGraph(timing_wire_graph, "./timing_wire_graph.yaml"); + + return timing_wire_graph; +} + +TimingInstanceGraph InitSTA::getTimingInstanceGraph() +{ + LOG_INFO << "get timing instance graph start"; + ieda::Stats stats; + + TimingInstanceGraph timing_instance_graph; + + auto* ista = STA_INST->get_ista(); + LOG_ERROR_IF(!ista->isBuildGraph()) << "timing graph is not build"; + + auto* the_timing_graph = &(ista->get_graph()); + + timing_instance_graph._edges.reserve(the_timing_graph->get_arcs().size() * 100); + timing_instance_graph._nodes.reserve(the_timing_graph->get_vertexes().size() * 10); + + /// create node in instance graph + auto create_node = [&timing_instance_graph](std::string& node_name) -> unsigned { + auto index = timing_instance_graph.findNode(node_name); + if (!index) { + TimingInstanceNode the_node; + the_node._name = node_name; + + index = timing_instance_graph.addNode(the_node); + } + + return index.value(); + }; + + ista::StaArc* the_arc; + FOREACH_ARC(the_timing_graph, the_arc) + { + if (the_arc->isNetArc()) { + auto* src_node = the_arc->get_src(); + auto* src_instance = src_node->get_design_obj()->get_own_instance(); + auto* snk_node = the_arc->get_snk(); + auto* snk_instance = snk_node->get_design_obj()->get_own_instance(); + + if (!src_instance || !snk_instance) { + continue; + } + + auto src_instance_name = src_instance->getFullName(); + auto snk_instance_name = snk_instance->getFullName(); + + unsigned src_node_index = create_node(src_instance_name); + unsigned snk_node_index = create_node(snk_instance_name); + + timing_instance_graph.addEdge(src_node_index, snk_node_index); + } + } + + LOG_INFO << "timing instance graph nodes " << timing_instance_graph._nodes.size(); + LOG_INFO << "timing instance graph edges " << timing_instance_graph._edges.size(); + + timing_instance_graph._nodes.shrink_to_fit(); + timing_instance_graph._edges.shrink_to_fit(); + + LOG_INFO << "get timing instance graph end"; + + LOG_INFO << "get timing instance graph memory usage " << stats.memoryDelta() << " MB"; + double total_time = stats.elapsedRunTime(); + LOG_INFO << "get timing instance graph elapsed time " << total_time << " s"; + + return timing_instance_graph; +} + +bool InitSTA::getRcNet(const std::string& net_name) +{ + auto netlist = STA_INST->get_netlist(); + ista::Net* ista_net = netlist->findNet(net_name.c_str()); + auto* rc_net = STA_INST->get_ista()->getRcNet(ista_net); + + return rc_net ? true : false; +} + +/// @brief Save wire timing graph to yaml file. +void SaveTimingGraph(const TimingWireGraph& timing_wire_graph, const std::string& json_file_name) +{ + LOG_INFO << "save wire timing graph start"; + + json nodes_json; + json edges_json; + + // for nodes + std::thread t1([&]() { + json j = json::array(); + for (unsigned node_id = 0; auto& node : timing_wire_graph._nodes) { + j.push_back({{"id", Str::printf("node_%d", node_id++)}, {"name", node._name}, {"is_pin", node._is_pin}, {"is_port", node._is_port}}); + } + nodes_json = j; + }); + + // for edges + std::thread t2([&]() { + json j = json::array(); + for (unsigned edge_id = 0; auto& edge : timing_wire_graph._edges) { + j.push_back({{"id", Str::printf("edge_%d", edge_id++)}, {"from_node", edge._from_node}, {"to_node", edge._to_node}, {"is_net_edge", edge._is_net_edge}}); + } + edges_json = j; + }); + + // wait to finish + t1.join(); + t2.join(); + + // merge + json graph_json; + graph_json["nodes"] = nodes_json; + graph_json["edges"] = edges_json; + + std::ofstream file(json_file_name, std::ios::trunc); + file << graph_json.dump(4) << std::endl; + + file.close(); + + LOG_INFO << "output wire graph json file path: " << json_file_name; + LOG_INFO << "save wire timing graph end"; +} + +void SaveTimingInstanceGraph(const TimingInstanceGraph& timing_instance_graph, const std::string& json_file_name) +{ + LOG_INFO << "save instance timing graph start"; + + json nodes_json; + json edges_json; + + // for nodes + std::thread t1([&]() { + json j = json::array(); + for (unsigned node_id = 0; auto& node : timing_instance_graph._nodes) { + j.push_back({{"id", Str::printf("node_%d", node_id++)}, {"name", node._name}}); + } + nodes_json = j; + }); + + // for edges + std::thread t2([&]() { + json j = json::array(); + for (unsigned edge_id = 0; auto& edge : timing_instance_graph._edges) { + j.push_back({{"id", Str::printf("edge_%d", edge_id++)}, {"from_node", edge._from_node}, {"to_node", edge._to_node}}); + } + edges_json = j; + }); + + // wait to finish + t1.join(); + t2.join(); + + // merge + json graph_json; + graph_json["nodes"] = nodes_json; + graph_json["edges"] = edges_json; + + std::ofstream file(json_file_name, std::ios::trunc); + file << graph_json.dump(4) << std::endl; + + file.close(); + + LOG_INFO << "output instance graph json file path: " << json_file_name; + LOG_INFO << "save instance timing graph end"; +} + +/// @brief Restore wire timing graph from yaml file. +/// @param yaml_file_name +/// @return +TimingWireGraph RestoreTimingGraph(const std::string& yaml_file_name) +{ + LOG_INFO << "restore wire timing graph start"; + TimingWireGraph timing_wire_graph; + + std::ifstream file(yaml_file_name); + string line; + + bool is_node = true; + TimingWireNode wire_node; + TimingWireEdge wire_edge; + + while (getline(file, line)) { + if (is_node && (line.rfind("edge_", 0) == 0)) { + is_node = false; + } + + if (is_node) { + if (line.find("name:") != string::npos) { + size_t pos = line.find(": "); + wire_node._name = line.substr(pos + 2); + } else if (line.find("is_pin:") != string::npos) { + size_t pos = line.find(": "); + wire_node._is_pin = stoi(line.substr(pos + 2)); + } else if (line.find("is_port:") != string::npos) { + size_t pos = line.find(": "); + wire_node._is_port = stoi(line.substr(pos + 2)); + timing_wire_graph._nodes.emplace_back(std::move(wire_node)); + } + + } else { + if (line.find("from_node:") != string::npos) { + size_t pos = line.find(": "); + wire_edge._from_node = stoll(line.substr(pos + 2)); + } else if (line.find("to_node:") != string::npos) { + size_t pos = line.find(": "); + wire_edge._to_node = stoll(line.substr(pos + 2)); + } else if (line.find("is_net_edge:") != string::npos) { + size_t pos = line.find(": "); + wire_edge._is_net_edge = stoi(line.substr(pos + 2)); + timing_wire_graph._edges.emplace_back(std::move(wire_edge)); + } + } + } + file.close(); + + LOG_INFO << "restore wire timing graph end"; + + LOG_INFO << "wire timing graph nodes " << timing_wire_graph._nodes.size(); + LOG_INFO << "wire timing graph edges " << timing_wire_graph._edges.size(); + + return timing_wire_graph; +} + +/// @brief Restore timing instance graph from yaml file. +/// @param yaml_file_name +/// @return +TimingInstanceGraph RestoreTimingInstanceGraph(const std::string& yaml_file_name) +{ + LOG_INFO << "restore timing instance graph start"; + TimingInstanceGraph timing_instance_graph; + + std::ifstream file(yaml_file_name); + string line; + + bool is_node = true; + TimingInstanceNode instance_node; + TimingNetEdge net_edge; + + while (getline(file, line)) { + if (is_node && (line.rfind("edge_", 0) == 0)) { + is_node = false; + } + + if (is_node) { + if (line.find("name:") != string::npos) { + size_t pos = line.find(": "); + instance_node._name = line.substr(pos + 2); + timing_instance_graph._nodes.emplace_back(std::move(instance_node)); + } + + } else { + if (line.find("from_node:") != string::npos) { + size_t pos = line.find(": "); + net_edge._from_node = stoll(line.substr(pos + 2)); + } else if (line.find("to_node:") != string::npos) { + size_t pos = line.find(": "); + net_edge._to_node = stoll(line.substr(pos + 2)); + + timing_instance_graph._edges.emplace_back(std::move(net_edge)); + } + } + } + file.close(); + + LOG_INFO << "restore timing instance graph end"; + + LOG_INFO << "timing instance graph nodes " << timing_instance_graph._nodes.size(); + LOG_INFO << "timing instance graph edges " << timing_instance_graph._edges.size(); + + return timing_instance_graph; +} + void InitSTA::updateTiming(const std::vector& timing_net_list, const std::vector& name_list, const int& propagation_level, int32_t dbu_unit) { @@ -674,7 +1377,8 @@ void InitSTA::updateTiming(const std::vector& timing_net_list, const } // int64_t wire_length = 0; - // wire_length = first_pin->get_coord().computeDist(second_pin->get_coord()); + // wire_length = + // first_pin->get_coord().computeDist(second_pin->get_coord()); int64_t wire_length = 0; wire_length = std::abs(first_pin->x - second_pin->x) + std::abs(first_pin->y - second_pin->y); @@ -704,4 +1408,276 @@ bool InitSTA::isClockNet(const std::string& net_name) const return STA_INST->isClockNet(net_name.c_str()); } +/** + * @brief The timing map of the patch. + * + * @param patch + * @return std::map + */ +std::map InitSTA::patchTimingMap(std::map, std::pair>>& patch) +{ + std::map patch_timing_map; + auto inst_timing_map = STA_INST->get_ista()->displayTimingMap(ista::AnalysisMode::kMax); + if (inst_timing_map.empty()) { + LOG_ERROR << "No instance timing map found."; + return patch_timing_map; + } + + auto* idb_adapter = STA_INST->getIDBAdapter(); + auto dbu = idb_adapter->get_dbu(); + + // 网格索引,减小搜索空间 + int64_t min_x = INT64_MAX; + int64_t max_x = INT64_MIN; + int64_t min_y = INT64_MAX; + int64_t max_y = INT64_MIN; + for (const auto& [coord, _] : inst_timing_map) { + int64_t x = static_cast(coord.first * dbu); + int64_t y = static_cast(coord.second * dbu); + min_x = std::min(min_x, x); + max_x = std::max(max_x, x); + min_y = std::min(min_y, y); + max_y = std::max(max_y, y); + } + + // 启发式确定网格大小 + int64_t grid_size_x = (max_x - min_x) / 100; + int64_t grid_size_y = (max_y - min_y) / 100; + + // 创建网格: 二维网格,每个网格内存有对应的insts + std::vector, double>>>> grid; + int64_t grid_width = (max_x - min_x) / grid_size_x + 1; + int64_t grid_height = (max_y - min_y) / grid_size_y + 1; + grid.resize(grid_width, std::vector, double>>>(grid_height)); + + // 填充网格 + for (const auto& [coord, slack] : inst_timing_map) { + int64_t x = static_cast(coord.first * dbu); + int64_t y = static_cast(coord.second * dbu); + int64_t grid_x = (x - min_x) / grid_size_x; + int64_t grid_y = (y - min_y) / grid_size_y; + grid[grid_x][grid_y].push_back({{x, y}, slack}); + } + + for (const auto& [patch_id, coord] : patch) { + auto [l_range, u_range] = coord; + const int64_t patch_lx = static_cast(l_range.first); + const int64_t patch_ly = static_cast(l_range.second); + const int64_t patch_ux = static_cast(u_range.first); + const int64_t patch_uy = static_cast(u_range.second); + + // 计算覆盖的网格范围 + int64_t start_grid_x = std::max(static_cast(0), (patch_lx - min_x) / grid_size_x); + int64_t end_grid_x = std::min(grid_width - 1, (patch_ux - min_x) / grid_size_x); + int64_t start_grid_y = std::max(static_cast(0), (patch_ly - min_y) / grid_size_y); + int64_t end_grid_y = std::min(grid_height - 1, (patch_uy - min_y) / grid_size_y); + + double min_slack = std::numeric_limits::max(); + + // 只检查覆盖的网格 + for (int64_t gx = start_grid_x; gx <= end_grid_x; ++gx) { + for (int64_t gy = start_grid_y; gy <= end_grid_y; ++gy) { + for (const auto& [inst_coord, inst_slack] : grid[gx][gy]) { + int64_t inst_x = inst_coord.first; + int64_t inst_y = inst_coord.second; + if (patch_lx <= inst_x && inst_x <= patch_ux && patch_ly <= inst_y && inst_y <= patch_uy) { + min_slack = std::min(min_slack, inst_slack); + } + } + } + } + + patch_timing_map[patch_id] = min_slack; + } + + return patch_timing_map; +} +/** + * @brief The power map of the patch. + * + * @param patch + * @return std::map + */ +std::map InitSTA::patchPowerMap(std::map, std::pair>>& patch) +{ + std::map patch_power_map; + auto inst_power_map = PW_INST->get_power()->displayInstancePowerMap(); + + if (inst_power_map.empty()) { + LOG_ERROR << "No instance power map found."; + return patch_power_map; + } + + auto* idb_adapter = STA_INST->getIDBAdapter(); + auto dbu = idb_adapter->get_dbu(); + + // 网格索引,减小搜索空间 + int64_t min_x = INT64_MAX; + int64_t max_x = INT64_MIN; + int64_t min_y = INT64_MAX; + int64_t max_y = INT64_MIN; + for (const auto& [coord, _] : inst_power_map) { + int64_t x = static_cast(coord.first * dbu); + int64_t y = static_cast(coord.second * dbu); + min_x = std::min(min_x, x); + max_x = std::max(max_x, x); + min_y = std::min(min_y, y); + max_y = std::max(max_y, y); + } + + // 启发式确定网格大小 + int64_t grid_size_x = (max_x - min_x) / 100; + int64_t grid_size_y = (max_y - min_y) / 100; + + // 创建网格: 二维网格,每个网格内存有对应的insts + std::vector, double>>>> grid; + int64_t grid_width = (max_x - min_x) / grid_size_x + 1; + int64_t grid_height = (max_y - min_y) / grid_size_y + 1; + grid.resize(grid_width, std::vector, double>>>(grid_height)); + + // 填充网格 + for (const auto& [coord, power] : inst_power_map) { + int64_t x = static_cast(coord.first * dbu); + int64_t y = static_cast(coord.second * dbu); + int64_t grid_x = (x - min_x) / grid_size_x; + int64_t grid_y = (y - min_y) / grid_size_y; + grid[grid_x][grid_y].push_back({{x, y}, power}); + } + + for (const auto& [patch_id, coord] : patch) { + auto [l_range, u_range] = coord; + const int64_t patch_lx = static_cast(l_range.first); + const int64_t patch_ly = static_cast(l_range.second); + const int64_t patch_ux = static_cast(u_range.first); + const int64_t patch_uy = static_cast(u_range.second); + + // 计算覆盖的网格范围 + int64_t start_grid_x = std::max(static_cast(0), (patch_lx - min_x) / grid_size_x); + int64_t end_grid_x = std::min(grid_width - 1, (patch_ux - min_x) / grid_size_x); + int64_t start_grid_y = std::max(static_cast(0), (patch_ly - min_y) / grid_size_y); + int64_t end_grid_y = std::min(grid_height - 1, (patch_uy - min_y) / grid_size_y); + + double total_power = 0.0; + + // 只检查覆盖的网格 + for (int64_t gx = start_grid_x; gx <= end_grid_x; ++gx) { + for (int64_t gy = start_grid_y; gy <= end_grid_y; ++gy) { + for (const auto& [inst_coord, inst_power] : grid[gx][gy]) { + int64_t inst_x = inst_coord.first; + int64_t inst_y = inst_coord.second; + if (patch_lx <= inst_x && inst_x <= patch_ux && patch_ly <= inst_y && inst_y <= patch_uy) { + total_power += inst_power; + } + } + } + } + + patch_power_map[patch_id] = total_power; + } + + return patch_power_map; +} + +/** + * @brief The ir drop map of the patch. + * + * @param patch + * @return std::map + */ +std::map InitSTA::patchIRDropMap(std::map, std::pair>>& patch) +{ + std::map patch_ir_drop_map; + for (const auto& [patch_id, _] : patch) { + patch_ir_drop_map[patch_id] = 0.0; + } + + // hard code std cell power net is VDD + std::string power_net_name = "VDD"; + PW_INST->runIRAnalysis(power_net_name); + auto instance_to_ir_drop = PW_INST->getInstanceIRDrop(); + + if (instance_to_ir_drop.empty()) { + LOG_WARNING << "No IR drop data available, returning zero values for all patches"; + return patch_ir_drop_map; + } + + auto* idb_adapter = STA_INST->getIDBAdapter(); + auto dbu = idb_adapter->get_dbu(); + + // 网格索引,减小搜索空间 + int64_t min_x = INT64_MAX; + int64_t max_x = INT64_MIN; + int64_t min_y = INT64_MAX; + int64_t max_y = INT64_MIN; + std::vector> instances; + instances.reserve(instance_to_ir_drop.size()); + + for (auto& [sta_inst, ir_drop] : instance_to_ir_drop) { + auto coord = sta_inst->get_coordinate().value(); + int64_t x = static_cast(coord.first * dbu); + int64_t y = static_cast(coord.second * dbu); + instances.emplace_back(x, y, ir_drop); + min_x = std::min(min_x, x); + max_x = std::max(max_x, x); + min_y = std::min(min_y, y); + max_y = std::max(max_y, y); + } + // 启发式确定网格大小 + int64_t grid_size_x = (max_x - min_x) / 100; + int64_t grid_size_y = (max_y - min_y) / 100; + + // 创建网格 + std::vector, double>>>> grid; + int64_t grid_width = (max_x - min_x) / grid_size_x + 1; + int64_t grid_height = (max_y - min_y) / grid_size_y + 1; + grid.resize(grid_width, std::vector, double>>>(grid_height)); + + // 填充网格 + for (const auto& [x, y, ir_drop] : instances) { + int64_t grid_x = (x - min_x) / grid_size_x; + int64_t grid_y = (y - min_y) / grid_size_y; + grid[grid_x][grid_y].push_back({{x, y}, ir_drop}); + } + + int processed_count = 0; + for (const auto& [patch_id, coord] : patch) { + auto [l_range, u_range] = coord; + const int64_t patch_lx = static_cast(l_range.first); + const int64_t patch_ly = static_cast(l_range.second); + const int64_t patch_ux = static_cast(u_range.first); + const int64_t patch_uy = static_cast(u_range.second); + + // 计算覆盖的网格范围 + int64_t start_grid_x = std::max(static_cast(0), (patch_lx - min_x) / grid_size_x); + int64_t end_grid_x = std::min(grid_width - 1, (patch_ux - min_x) / grid_size_x); + int64_t start_grid_y = std::max(static_cast(0), (patch_ly - min_y) / grid_size_y); + int64_t end_grid_y = std::min(grid_height - 1, (patch_uy - min_y) / grid_size_y); + + double max_ir_drop = 0.0; + + // 只检查覆盖的网格 + for (int64_t gx = start_grid_x; gx <= end_grid_x; ++gx) { + for (int64_t gy = start_grid_y; gy <= end_grid_y; ++gy) { + for (const auto& [inst_coord, inst_ir_drop] : grid[gx][gy]) { + int64_t inst_x = inst_coord.first; + int64_t inst_y = inst_coord.second; + if (patch_lx <= inst_x && inst_x <= patch_ux && patch_ly <= inst_y && inst_y <= patch_uy) { + max_ir_drop = std::max(max_ir_drop, inst_ir_drop); + } + } + } + } + + patch_ir_drop_map[patch_id] = max_ir_drop; + + // 每处理5000个patch输出一次日志 + processed_count++; + if (processed_count % 5000 == 0) { + LOG_INFO << "Processed " << processed_count << " patches out of " << patch.size(); + } + } + + return patch_ir_drop_map; +} + } // namespace ieval \ No newline at end of file diff --git a/src/evaluation/src/util/init_sta.hh b/src/evaluation/src/util/init_sta.hh index 30740d2fabaaa64e7a90d3862a4b97d961700f81..aa4fe4aca8ac4db3de96db7f723c8b0d9e9221e9 100644 --- a/src/evaluation/src/util/init_sta.hh +++ b/src/evaluation/src/util/init_sta.hh @@ -28,6 +28,7 @@ #include #include #include +#include namespace ista { enum class AnalysisMode; @@ -35,10 +36,127 @@ enum class AnalysisMode; namespace salt { class Pin; } + +namespace ivec { +class VecLayout; +} + namespace ieval { struct TimingNet; +/// @brief The timing wire graph for weiguo used. +struct TimingWireNode +{ + std::string _name; //!< for pin/port name or node id. + bool _is_pin = false; + bool _is_port = false; +}; + +struct TimingWireEdge +{ + int64_t _from_node = -1; + int64_t _to_node = -1; + bool _is_net_edge = true; +}; + + +/// @brief The timing instance node for wangrui used. +struct TimingInstanceNode { + std::string _name; //!< instance name +}; + +struct TimingNetEdge { + int64_t _from_node = -1; + int64_t _to_node = -1; +}; + +template +struct TimingGraph +{ + std::vector _nodes; //!< each one is a graph node + std::vector _edges; + + private: + std::map _node2index_map; //!< node name to node index map. + std::map, unsigned> _edge2index_map; //!< edge from/to node index to edge index map. + + public: + std::optional findNode(std::string& node_name) + { + if (_node2index_map.find(node_name) == _node2index_map.end()) { + return std::nullopt; + } + + return _node2index_map[node_name]; + } + + unsigned addNode(const T& node) + { + _nodes.push_back(node); + unsigned index = _nodes.size() - 1; + _node2index_map[node._name] = index; + + return index; + } + + U* findEdge(unsigned wire_from_node_index, unsigned wire_to_node_index) + { + auto edge_key = std::make_pair(wire_from_node_index, wire_to_node_index); + if (_edge2index_map.find(edge_key) == _edge2index_map.end()) { + return nullptr; + } + + return &(_edges[_edge2index_map[edge_key]]); + } + + U& addEdge(unsigned wire_from_node_index, unsigned wire_to_node_index) + { + U wire_graph_edge; + + wire_graph_edge._from_node = wire_from_node_index; + wire_graph_edge._to_node = wire_to_node_index; + + auto edge_key = std::make_pair(wire_from_node_index, wire_to_node_index); + if (_edge2index_map.find(edge_key) != _edge2index_map.end()) + { + return _edges[_edge2index_map[edge_key]]; + } + + _edge2index_map[edge_key] = _edges.size(); + + return _edges.emplace_back(std::move(wire_graph_edge)); + } +}; + + +/** + * @brief The timing wire graph for weiguo used. + */ +struct TimingWireGraph : public TimingGraph { + +}; + +/** + * @brief The timing instance graph for wangrui used. + */ +struct TimingInstanceGraph : public TimingGraph { + +}; + +/// @brief save timing graph to yaml file. +/// @param timing_wire_graph +/// @param yaml_file_name +void SaveTimingGraph(const TimingWireGraph& timing_wire_graph, const std::string& json_file_name); + +/// @brief restore timing graph from yaml file. +TimingWireGraph RestoreTimingGraph(const std::string& yaml_file_name); + +/// @brief save timing instance graph to yaml file. +void SaveTimingInstanceGraph(const TimingInstanceGraph& timing_instance_graph, const std::string& json_file_name); +/// @brief restore timing instance graph from yaml file. +TimingInstanceGraph RestoreTimingInstanceGraph(const std::string& yaml_file_name); + class InitSTA { public: @@ -46,7 +164,9 @@ class InitSTA ~InitSTA(); static InitSTA* getInst(); static void destroyInst(); + void runSTA(); + void runVecSTA(ivec::VecLayout* vec_layout, std::string work_dir); void evalTiming(const std::string& routing_type, const bool& rt_done = false); std::map>> getTiming() const { return _timing; } @@ -63,19 +183,43 @@ class InitSTA double reportWNS(const char* clock_name, ista::AnalysisMode mode); double reportTNS(const char* clock_name, ista::AnalysisMode mode); + // for net R、C、slew、delay power. + double getNetResistance(const std::string& net_name) const; + double getNetCapacitance(const std::string& net_name) const; + double getNetSlew(const std::string& net_name) const; + std::map getAllNodesSlew(const std::string& net_name) const; + double getNetDelay(const std::string& net_name) const; + std::pair getNetToggleAndVoltage(const std::string& net_name) const; + double getNetPower(const std::string& net_name) const; + + // for wire R、C、slew、delay power. + double getWireResistance(const std::string& net_name, const std::string& wire_node_name) const; + double getWireCapacitance(const std::string& net_name, const std::string& wire_node_name) const; + double getWireDelay(const std::string& net_name, const std::string& wire_node_name) const; + // double getWirePower(const std::string& net_name, const std::string& wire_node_name) const; + TimingWireGraph getTimingWireGraph(); + TimingInstanceGraph getTimingInstanceGraph(); + + bool getRcNet(const std::string& net_name); + + void buildRCTree(const std::string& routing_type); + void buildVecRCTree(ivec::VecLayout* vec_layout, std::string work_dir); void updateTiming(const std::vector& timing_net_list, int32_t dbu_unit); void updateTiming(const std::vector& timing_net_list, const std::vector& name_list, const int& propagation_level, int32_t dbu_unit); bool isClockNet(const std::string& net_name) const; + std::map patchTimingMap(std::map, std::pair>>& patch); + std::map patchPowerMap(std::map, std::pair>>& patch); + std::map patchIRDropMap(std::map, std::pair>>& patch); + private: void leaglization(const std::vector>& pins); void initStaEngine(); void callRT(const std::string& routing_type); - void buildRCTree(const std::string& routing_type); - void initPowerEngine(); + void initPowerEngine(); void updateResult(const std::string& routing_type); static InitSTA* _init_sta; diff --git a/src/feature/builder/feature_eval_union.cpp b/src/feature/builder/feature_eval_union.cpp index e5060c409750c8db34e3ffffc99af5427ad3e28d..fc315460b96a9d189d9f2ad76cc04d3252f2cf18 100644 --- a/src/feature/builder/feature_eval_union.cpp +++ b/src/feature/builder/feature_eval_union.cpp @@ -24,7 +24,7 @@ UnionEvalSummary FeatureBuilder::buildUnionEvalSummary(int32_t grid_size, std::s UnionEvalSummary union_eval_summary; TotalWLSummary total_wl_summary; - ieval::TotalWLSummary eval_total_wl_summary = WIRELENGTH_API_INST->totalWLPure(); + ieval::TotalWLSummary eval_total_wl_summary = WIRELENGTH_API_INST->totalWLPure(); total_wl_summary.HPWL = eval_total_wl_summary.HPWL; total_wl_summary.FLUTE = eval_total_wl_summary.FLUTE; total_wl_summary.HTree = eval_total_wl_summary.HTree; @@ -43,7 +43,7 @@ UnionEvalSummary FeatureBuilder::buildUnionEvalSummary(int32_t grid_size, std::s density_map_summary.net_map_summary.global_net_density = eval_density_map_summary.net_map_summary.global_net_density; density_map_summary.net_map_summary.allnet_density = eval_density_map_summary.net_map_summary.allnet_density; if (stage == "place") { - ieval::MacroMarginSummary eval_macro_margin_summary = DENSITY_API_INST->macroMarginMap(grid_size); + ieval::MacroMarginSummary eval_macro_margin_summary = DENSITY_API_INST->macroMarginMap(grid_size, stage); density_map_summary.macro_margin_summary.horizontal_margin = eval_macro_margin_summary.horizontal_margin; density_map_summary.macro_margin_summary.vertical_margin = eval_macro_margin_summary.vertical_margin; density_map_summary.macro_margin_summary.union_margin = eval_macro_margin_summary.union_margin; diff --git a/src/feature/database/feature_ipl.h b/src/feature/database/feature_ipl.h index 64ca8f0011b5b452485515c0c3e993da9ef99ab1..7934034a3d7896a6db61e7ff912e56936f2d6d22 100644 --- a/src/feature/database/feature_ipl.h +++ b/src/feature/database/feature_ipl.h @@ -23,18 +23,8 @@ namespace ieda_feature { struct PLCommonSummary { float place_density; - // float pin_density; - // int64_t HPWL; - // int64_t STWL; - // int64_t GRWL; - - // int32_t egr_tof; - // int32_t egr_mof; - // float egr_ace; - - // float tns; - // float wns; - // float suggest_freq; + int64_t HPWL; + int64_t STWL; }; struct LGSummary diff --git a/src/feature/database/feature_irt.h b/src/feature/database/feature_irt.h index a7515b6c9772d2a839efd1997268a6e7dcd3720a..8717d4f63a8fee59c5361c9743d71fed82e1e7cd 100644 --- a/src/feature/database/feature_irt.h +++ b/src/feature/database/feature_irt.h @@ -28,8 +28,6 @@ namespace ieda_feature { /// ###################################################################################/// struct PASummary { - std::map routing_access_point_num_map; - int32_t total_access_point_num = 0; std::map routing_wire_length_map; double total_wire_length = 0; std::map cut_via_num_map; @@ -51,8 +49,8 @@ struct TGSummary double total_demand = 0; double total_overflow = 0; double total_wire_length = 0; - std::map> clock_timing; - std::map power_map; + std::map> clock_timing_map; + std::map type_power_map; }; struct LASummary @@ -65,8 +63,8 @@ struct LASummary double total_wire_length = 0; std::map cut_via_num_map; int32_t total_via_num = 0; - std::map> clock_timing; - std::map power_map; + std::map> clock_timing_map; + std::map type_power_map; }; struct SRSummary @@ -79,8 +77,8 @@ struct SRSummary double total_wire_length = 0; std::map cut_via_num_map; int32_t total_via_num = 0; - std::map> clock_timing; - std::map power_map; + std::map> clock_timing_map; + std::map type_power_map; }; struct TASummary @@ -101,8 +99,8 @@ struct DRSummary int32_t total_patch_num = 0; std::map routing_violation_num_map; int32_t total_violation_num = 0; - std::map> clock_timing; - std::map power_map; + std::map> clock_timing_map; + std::map type_power_map; }; struct VRSummary @@ -121,8 +119,8 @@ struct VRSummary std::map among_net_violation_type_num_map; std::map among_net_routing_violation_num_map; int32_t among_net_total_violation_num = 0; - std::map> clock_timing; - std::map power_map; + std::map> clock_timing_map; + std::map type_power_map; }; struct ERSummary @@ -135,8 +133,8 @@ struct ERSummary double total_wire_length = 0; std::map cut_via_num_map; int32_t total_via_num = 0; - std::map> clock_timing; - std::map power_map; + std::map> clock_timing_map; + std::map type_power_map; }; struct RTSummary diff --git a/src/feature/feature_manager.cpp b/src/feature/feature_manager.cpp index 239c240a980045a0a451e2f5a9011f9297ccdeb8..8735dae38e1fd8a464f077d4f55d8112ac01aa50 100644 --- a/src/feature/feature_manager.cpp +++ b/src/feature/feature_manager.cpp @@ -60,7 +60,7 @@ bool FeatureManager::save_eval_summary(std::string path, int32_t grid_size) _summary->set_timing_eval(timing_db); FeatureParser feature_parser(_summary); - return feature_parser.buildSummaryEvalJsonl(path); + return feature_parser.buildSummaryEval(path); } bool FeatureManager::save_eval_union(std::string jsonl_path, std::string csv_path, int32_t grid_size) @@ -81,7 +81,7 @@ bool FeatureManager::save_eval_union(std::string jsonl_path, std::string csv_pat // bool csv_success = true; // FeatureParser feature_parser(_summary); - // bool jsonl_success = feature_parser.buildSummaryEvalJsonl(jsonl_path); + // bool jsonl_success = feature_parser.buildSummaryEval(jsonl_path); bool jsonl_success = true; builder.destroyEvalTool(); @@ -89,7 +89,7 @@ bool FeatureManager::save_eval_union(std::string jsonl_path, std::string csv_pat return jsonl_success && csv_success; } -bool FeatureManager::save_pl_eval_union(std::string jsonl_path, std::string csv_path, int32_t grid_size) +bool FeatureManager::save_pl_eval(std::string json_path, int32_t grid_size) { // EGR FeatureBuilder builder; @@ -107,7 +107,6 @@ bool FeatureManager::save_pl_eval_union(std::string jsonl_path, std::string csv_ _summary->set_congestion_eval(union_db.congestion_summary); // builder.evalTiming("EGR", true); - // builder.evalTiming("HPWL"); // builder.evalTiming("FLUTE"); // builder.evalTiming("SALT"); @@ -116,15 +115,14 @@ bool FeatureManager::save_pl_eval_union(std::string jsonl_path, std::string csv_ // _summary->set_timing_eval(union_timing_db); FeatureParser feature_parser(_summary); - bool jsonl_success = feature_parser.buildSummaryEvalJsonl(jsonl_path); - bool csv_success = builder.buildNetEval(csv_path); + bool json_success = feature_parser.buildSummaryEval(json_path); builder.destroyEvalTool(); - return jsonl_success && csv_success; + return json_success; } -bool FeatureManager::save_cts_eval_union(std::string jsonl_path, std::string csv_path, int32_t grid_size) +bool FeatureManager::save_cts_eval(std::string json_path, int32_t grid_size) { // EGR FeatureBuilder builder; @@ -141,23 +139,21 @@ bool FeatureManager::save_cts_eval_union(std::string jsonl_path, std::string csv _summary->set_density_eval(union_db.density_map_summary); _summary->set_congestion_eval(union_db.congestion_summary); - builder.evalTiming("EGR", true); + // builder.evalTiming("EGR", true); - builder.evalTiming("HPWL"); - builder.evalTiming("FLUTE"); - builder.evalTiming("SALT"); + // builder.evalTiming("HPWL"); + // builder.evalTiming("FLUTE"); + // builder.evalTiming("SALT"); - auto union_timing_db = builder.buildTimingUnionEvalSummary(); - _summary->set_timing_eval(union_timing_db); + // auto union_timing_db = builder.buildTimingUnionEvalSummary(); + // _summary->set_timing_eval(union_timing_db); FeatureParser feature_parser(_summary); - bool jsonl_success = feature_parser.buildSummaryEvalJsonl(jsonl_path); - - bool csv_success = builder.buildNetEval(csv_path); + bool json_success = feature_parser.buildSummaryEval(json_path); builder.destroyEvalTool(); - return jsonl_success && csv_success; + return json_success; } bool FeatureManager::save_timing_eval_summary(std::string path) diff --git a/src/feature/feature_manager.h b/src/feature/feature_manager.h index c1d2ebbce4e0a5923ffc8c71b90225b182500297..2216ad7e5b9d9296d74694d1454458490bed0acd 100644 --- a/src/feature/feature_manager.h +++ b/src/feature/feature_manager.h @@ -70,8 +70,8 @@ class FeatureManager bool save_eval_summary(std::string path, int32_t grid_size); bool save_timing_eval_summary(std::string path); bool save_eval_union(std::string jsonl_path, std::string csv_path, int32_t grid_size); - bool save_pl_eval_union(std::string jsonl_path, std::string csv_path, int32_t grid_size); - bool save_cts_eval_union(std::string jsonl_path, std::string csv_path, int32_t grid_size); + bool save_pl_eval(std::string json_path, int32_t grid_size = 1); + bool save_cts_eval(std::string json_path, int32_t grid_size = 1); private: static FeatureManager* _instance; diff --git a/src/feature/parser/feature_parser.cpp b/src/feature/parser/feature_parser.cpp index b529d9571d568fc2b51893f0f73a7ddbb6d2c6d9..47cd1583fda081304135576fd27639f68a17cf54 100644 --- a/src/feature/parser/feature_parser.cpp +++ b/src/feature/parser/feature_parser.cpp @@ -216,9 +216,9 @@ bool FeatureParser::buildSummaryEval(std::string json_path) root["Congestion"] = buildSummaryCongestion(); - root["Timing"] = buildSummaryTiming(); + // root["Timing"] = buildSummaryTiming(); - root["Power"] = buildSummaryPower(); + // root["Power"] = buildSummaryPower(); file_stream << std::setw(4) << root; @@ -228,35 +228,6 @@ bool FeatureParser::buildSummaryEval(std::string json_path) return true; } -bool FeatureParser::buildSummaryEvalJsonl(std::string jsonl_path) -{ - std::ofstream& file_stream = ieda::getOutputFileStream(jsonl_path); - - json wirelength; - wirelength["Wirelength"] = buildSummaryWirelength(); - file_stream << wirelength << std::endl; - - json density; - density["Density"] = buildSummaryDensity(); - file_stream << density << std::endl; - - json congestion; - congestion["Congestion"] = buildSummaryCongestion(); - file_stream << congestion << std::endl; - - // json timing; - // timing["Timing"] = buildSummaryTiming(); - // file_stream << timing << std::endl; - - // json power; - // power["Power"] = buildSummaryPower(); - // file_stream << power << std::endl; - - ieda::closeFileStream(file_stream); - - std::cout << std::endl << "Save eval jsonl success, path = " << jsonl_path << std::endl; - return true; -} bool FeatureParser::buildSummaryTimingEval(std::string json_path) { diff --git a/src/feature/parser/feature_parser.h b/src/feature/parser/feature_parser.h index 0c37454301a552548628ab4189449943459a5db9..e3a790aed4923de558b830e8160ef428e747eab9 100644 --- a/src/feature/parser/feature_parser.h +++ b/src/feature/parser/feature_parser.h @@ -69,7 +69,6 @@ class FeatureParser bool readRouteData(std::string json_path, RouteAnalyseData* data); bool buildSummaryEval(std::string json_path); - bool buildSummaryEvalJsonl(std::string jsonl_path); bool buildSummaryTimingEval(std::string json_path); bool buildNetEval(std::string csv_path); bool buildCongMap(std::string stage, std::string csv_dir); diff --git a/src/feature/parser/feature_parser_eval.cpp b/src/feature/parser/feature_parser_eval.cpp index 7135dc0a19c18e2ff1e819f69f1ff7a91f0301de..e351d1faa23997815182cba588e8fac8759ee513 100644 --- a/src/feature/parser/feature_parser_eval.cpp +++ b/src/feature/parser/feature_parser_eval.cpp @@ -193,29 +193,29 @@ json FeatureParser::buildSummaryCongestion() congestion_info["overflow"]["max"]["vertical"] = congestion_summary.overflow_summary.max_overflow_vertical; congestion_info["overflow"]["max"]["union"] = congestion_summary.overflow_summary.max_overflow_union; - congestion_info["overflow"]["top average"]["horizontal"] = congestion_summary.overflow_summary.weighted_average_overflow_horizontal; - congestion_info["overflow"]["top average"]["vertical"] = congestion_summary.overflow_summary.weighted_average_overflow_vertical; - congestion_info["overflow"]["top average"]["union"] = congestion_summary.overflow_summary.weighted_average_overflow_union; + congestion_info["overflow"]["top_average"]["horizontal"] = congestion_summary.overflow_summary.weighted_average_overflow_horizontal; + congestion_info["overflow"]["top_average"]["vertical"] = congestion_summary.overflow_summary.weighted_average_overflow_vertical; + congestion_info["overflow"]["top_average"]["union"] = congestion_summary.overflow_summary.weighted_average_overflow_union; congestion_info["utilization"]["rudy"]["max"]["horizontal"] = congestion_summary.rudy_utilization_summary.max_utilization_horizontal; congestion_info["utilization"]["rudy"]["max"]["vertical"] = congestion_summary.rudy_utilization_summary.max_utilization_vertical; congestion_info["utilization"]["rudy"]["max"]["union"] = congestion_summary.rudy_utilization_summary.max_utilization_union; - congestion_info["utilization"]["rudy"]["top average"]["horizontal"] + congestion_info["utilization"]["rudy"]["top_average"]["horizontal"] = congestion_summary.rudy_utilization_summary.weighted_average_utilization_horizontal; - congestion_info["utilization"]["rudy"]["top average"]["vertical"] + congestion_info["utilization"]["rudy"]["top_average"]["vertical"] = congestion_summary.rudy_utilization_summary.weighted_average_utilization_vertical; - congestion_info["utilization"]["rudy"]["top average"]["union"] + congestion_info["utilization"]["rudy"]["top_average"]["union"] = congestion_summary.rudy_utilization_summary.weighted_average_utilization_union; congestion_info["utilization"]["lutrudy"]["max"]["horizontal"] = congestion_summary.lutrudy_utilization_summary.max_utilization_horizontal; congestion_info["utilization"]["lutrudy"]["max"]["vertical"] = congestion_summary.lutrudy_utilization_summary.max_utilization_vertical; congestion_info["utilization"]["lutrudy"]["max"]["union"] = congestion_summary.lutrudy_utilization_summary.max_utilization_union; - congestion_info["utilization"]["lutrudy"]["top average"]["horizontal"] + congestion_info["utilization"]["lutrudy"]["top_average"]["horizontal"] = congestion_summary.lutrudy_utilization_summary.weighted_average_utilization_horizontal; - congestion_info["utilization"]["lutrudy"]["top average"]["vertical"] + congestion_info["utilization"]["lutrudy"]["top_average"]["vertical"] = congestion_summary.lutrudy_utilization_summary.weighted_average_utilization_vertical; - congestion_info["utilization"]["lutrudy"]["top average"]["union"] + congestion_info["utilization"]["lutrudy"]["top_average"]["union"] = congestion_summary.lutrudy_utilization_summary.weighted_average_utilization_union; return congestion_info; diff --git a/src/feature/parser/feature_parser_tools.cpp b/src/feature/parser/feature_parser_tools.cpp index 89f25ac203fa25c2a9aca6807610384707ef03fb..215fca296f07be0ec8cfe414d2cfcfdb88a73d62 100644 --- a/src/feature/parser/feature_parser_tools.cpp +++ b/src/feature/parser/feature_parser_tools.cpp @@ -40,206 +40,239 @@ json FeatureParser::buildSummaryRT() { json json_rt; -#if 0 - - RTSummary& rt_sum = _summary->get_summary_irt(); - - /// PA - json json_pa; - json_pa["total_access_point_num"] = rt_sum.pa_summary.total_access_point_num; - for (auto routing_access_point_num : rt_sum.pa_summary.routing_access_point_num_map) { - json_pa["routing_access_point_num_map"][std::to_string(routing_access_point_num.first)] = routing_access_point_num.second; - } - for (auto type_access_point_num : rt_sum.pa_summary.type_access_point_num_map) { - json_pa["type_access_point_num_map"][type_access_point_num.first] = type_access_point_num.second; - } - json_rt["PA"] = json_pa; - - /// SA - json json_sa; - json_sa["total_supply"] = rt_sum.sa_summary.total_supply; - - for (auto routing_supply_num : rt_sum.sa_summary.routing_supply_map) { - json_sa["routing_supply_map"][std::to_string(routing_supply_num.first)] = routing_supply_num.second; - } - json_rt["SA"] = json_sa; - - // TG - json json_tg; - json_tg["total_demand"] = rt_sum.tg_summary.total_demand; - json_tg["total_overflow"] = rt_sum.tg_summary.total_overflow; - json_tg["total_wire_length"] = rt_sum.tg_summary.total_wire_length; - - for (int i = 0; i < (int) rt_sum.tg_summary.clocks_timing.size(); i++) { - auto clock_timing = rt_sum.tg_summary.clocks_timing[i]; - json_tg["clocks_timing"][i]["clock_name"] = clock_timing.clock_name; - json_tg["clocks_timing"][i]["setup_tns"] = clock_timing.setup_tns; - json_tg["clocks_timing"][i]["setup_wns"] = clock_timing.setup_wns; - json_tg["clocks_timing"][i]["suggest_freq"] = clock_timing.suggest_freq; - } - json_tg["static_power"] = rt_sum.tg_summary.power_info.static_power; - json_tg["dynamic_power"] = rt_sum.tg_summary.power_info.dynamic_power; - json_rt["TG"] = json_tg; - - /// LA - json json_la; - json_la["total_demand"] = rt_sum.la_summary.total_demand; - for (auto demand : rt_sum.la_summary.routing_demand_map) { - json_la["routing_demand_map"][std::to_string(demand.first)] = demand.second; - } - - json_la["total_overflow"] = rt_sum.la_summary.total_overflow; - for (auto routing_overflow : rt_sum.la_summary.routing_overflow_map) { - json_la["routing_overflow_map"][std::to_string(routing_overflow.first)] = routing_overflow.second; - } - - json_la["total_wire_length"] = rt_sum.la_summary.total_wire_length; - for (auto routing_wire_length : rt_sum.la_summary.routing_wire_length_map) { - json_la["routing_wire_length_map"][std::to_string(routing_wire_length.first)] = routing_wire_length.second; + RTSummary& summary_irt = _summary->get_summary_irt(); + + { + // PASummary + std::vector pa_json_list; + for (auto [iter, pa_summary] : summary_irt.iter_pa_summary_map) { + json pa_json; + pa_json["iter"] = iter; + for (auto& [routing_layer_idx, wire_length] : pa_summary.routing_wire_length_map) { + pa_json["routing_wire_length_map"][std::to_string(routing_layer_idx)] = wire_length; + } + pa_json["total_wire_length"] = pa_summary.total_wire_length; + for (auto& [cut_layer_idx, via_num] : pa_summary.cut_via_num_map) { + pa_json["cut_via_num_map"][std::to_string(cut_layer_idx)] = via_num; + } + pa_json["total_via_num"] = pa_summary.total_via_num; + for (auto& [routing_layer_idx, patch_num] : pa_summary.routing_patch_num_map) { + pa_json["routing_patch_num_map"][std::to_string(routing_layer_idx)] = patch_num; + } + pa_json["total_patch_num"] = pa_summary.total_patch_num; + for (auto& [routing_layer_idx, violation_num] : pa_summary.routing_violation_num_map) { + pa_json["routing_violation_num_map"][std::to_string(routing_layer_idx)] = violation_num; + } + pa_json["total_violation_num"] = pa_summary.total_violation_num; + pa_json_list.push_back(pa_json); + } + json_rt["PA"] = pa_json_list; } - json_la["total_via_num"] = rt_sum.la_summary.total_via_num; - for (auto cut_via_num : rt_sum.la_summary.cut_via_num_map) { - json_la["cut_via_num_map"][std::to_string(cut_via_num.first)] = cut_via_num.second; + { + // SASummary + json sa_json; + for (auto& [routing_layer_idx, supply] : summary_irt.sa_summary.routing_supply_map) { + sa_json["routing_supply_map"][std::to_string(routing_layer_idx)] = supply; + } + sa_json["total_supply"] = summary_irt.sa_summary.total_supply; + json_rt["SA"] = sa_json; } - for (int i = 0; i < (int) rt_sum.la_summary.clocks_timing.size(); i++) { - auto clock_timing = rt_sum.la_summary.clocks_timing[i]; - json_la["clocks_timing"][i]["clock_name"] = clock_timing.clock_name; - json_la["clocks_timing"][i]["setup_tns"] = clock_timing.setup_tns; - json_la["clocks_timing"][i]["setup_wns"] = clock_timing.setup_wns; - json_la["clocks_timing"][i]["suggest_freq"] = clock_timing.suggest_freq; + { + // TGSummary + json tg_json; + tg_json["total_demand"] = summary_irt.tg_summary.total_demand; + tg_json["total_overflow"] = summary_irt.tg_summary.total_overflow; + tg_json["total_wire_length"] = summary_irt.tg_summary.total_wire_length; + for (auto& [clock_name, timing] : summary_irt.tg_summary.clock_timing_map) { + tg_json["clock_timing_map"]["clock_name"] = clock_name; + tg_json["clock_timing_map"]["timing"] = timing; + } + for (auto& [type, power] : summary_irt.tg_summary.type_power_map) { + tg_json["type_power_map"]["type"] = type; + tg_json["type_power_map"]["power"] = power; + } + json_rt["TG"] = tg_json; } - json_la["static_power"] = rt_sum.la_summary.power_info.static_power; - json_la["dynamic_power"] = rt_sum.la_summary.power_info.dynamic_power; - json_rt["LA"] = json_la; - - // ER - json json_er; - json_er["total_demand"] = rt_sum.la_summary.total_demand; - for (auto demand : rt_sum.la_summary.routing_demand_map) { - json_er["routing_demand_map"][std::to_string(demand.first)] = demand.second; + { + // LASummary + json la_json; + for (auto& [routing_layer_idx, demand] : summary_irt.la_summary.routing_demand_map) { + la_json["routing_demand_map"][std::to_string(routing_layer_idx)] = demand; + } + la_json["total_demand"] = summary_irt.la_summary.total_demand; + for (auto& [routing_layer_idx, overflow] : summary_irt.la_summary.routing_overflow_map) { + la_json["routing_overflow_map"][std::to_string(routing_layer_idx)] = overflow; + } + la_json["total_overflow"] = summary_irt.la_summary.total_overflow; + for (auto& [routing_layer_idx, wire_length] : summary_irt.la_summary.routing_wire_length_map) { + la_json["routing_wire_length_map"][std::to_string(routing_layer_idx)] = wire_length; + } + la_json["total_wire_length"] = summary_irt.la_summary.total_wire_length; + for (auto& [cut_layer_idx, via_num] : summary_irt.la_summary.cut_via_num_map) { + la_json["cut_via_num_map"][std::to_string(cut_layer_idx)] = via_num; + } + la_json["total_via_num"] = summary_irt.la_summary.total_via_num; + for (auto& [clock_name, timing] : summary_irt.la_summary.clock_timing_map) { + la_json["clock_timing_map"]["clock_name"] = clock_name; + la_json["clock_timing_map"]["timing"] = timing; + } + for (auto& [type, power] : summary_irt.la_summary.type_power_map) { + la_json["type_power_map"]["type"] = type; + la_json["type_power_map"]["power"] = power; + } + json_rt["LA"] = la_json; } - json_er["total_overflow"] = rt_sum.la_summary.total_overflow; - for (auto routing_overflow : rt_sum.la_summary.routing_overflow_map) { - json_er["routing_overflow_map"][std::to_string(routing_overflow.first)] = routing_overflow.second; + { + // SRSummary + std::vector sr_json_list; + for (auto [iter, sr_summary] : summary_irt.iter_sr_summary_map) { + json sr_json; + sr_json["iter"] = iter; + for (auto& [routing_layer_idx, demand] : sr_summary.routing_demand_map) { + sr_json["routing_demand_map"][std::to_string(routing_layer_idx)] = demand; + } + sr_json["total_demand"] = sr_summary.total_demand; + for (auto& [routing_layer_idx, overflow] : sr_summary.routing_overflow_map) { + sr_json["routing_overflow_map"][std::to_string(routing_layer_idx)] = overflow; + } + sr_json["total_overflow"] = sr_summary.total_overflow; + for (auto& [routing_layer_idx, wire_length] : sr_summary.routing_wire_length_map) { + sr_json["routing_wire_length_map"][std::to_string(routing_layer_idx)] = wire_length; + } + sr_json["total_wire_length"] = sr_summary.total_wire_length; + for (auto& [cut_layer_idx, via_num] : sr_summary.cut_via_num_map) { + sr_json["cut_via_num_map"][std::to_string(cut_layer_idx)] = via_num; + } + sr_json["total_via_num"] = sr_summary.total_via_num; + for (auto& [clock_name, timing] : sr_summary.clock_timing_map) { + sr_json["clock_timing_map"]["clock_name"] = clock_name; + sr_json["clock_timing_map"]["timing"] = timing; + } + for (auto& [type, power] : sr_summary.type_power_map) { + sr_json["type_power_map"]["type"] = type; + sr_json["type_power_map"]["power"] = power; + } + sr_json_list.push_back(sr_json); + } + json_rt["SR"] = sr_json_list; } - json_er["total_wire_length"] = rt_sum.la_summary.total_wire_length; - for (auto routing_wire_length : rt_sum.la_summary.routing_wire_length_map) { - json_er["routing_wire_length_map"][std::to_string(routing_wire_length.first)] = routing_wire_length.second; + { + // TASummary + json ta_json; + for (auto& [routing_layer_idx, wire_length] : summary_irt.ta_summary.routing_wire_length_map) { + ta_json["routing_wire_length_map"][std::to_string(routing_layer_idx)] = wire_length; + } + ta_json["total_wire_length"] = summary_irt.ta_summary.total_wire_length; + for (auto& [routing_layer_idx, violation_num] : summary_irt.ta_summary.routing_violation_num_map) { + ta_json["routing_violation_num_map"][std::to_string(routing_layer_idx)] = violation_num; + } + ta_json["total_violation_num"] = summary_irt.ta_summary.total_violation_num; + json_rt["TA"] = ta_json; } - json_er["total_via_num"] = rt_sum.la_summary.total_via_num; - for (auto cut_via_num : rt_sum.la_summary.cut_via_num_map) { - json_er["cut_via_num_map"][std::to_string(cut_via_num.first)] = cut_via_num.second; + { + // DRSummary + std::vector dr_json_list; + for (auto [iter, dr_summary] : summary_irt.iter_dr_summary_map) { + json dr_json; + dr_json["iter"] = iter; + for (auto& [routing_layer_idx, wire_length] : dr_summary.routing_wire_length_map) { + dr_json["routing_wire_length_map"][std::to_string(routing_layer_idx)] = wire_length; + } + dr_json["total_wire_length"] = dr_summary.total_wire_length; + for (auto& [cut_layer_idx, via_num] : dr_summary.cut_via_num_map) { + dr_json["cut_via_num_map"][std::to_string(cut_layer_idx)] = via_num; + } + dr_json["total_via_num"] = dr_summary.total_via_num; + for (auto& [routing_layer_idx, patch_num] : dr_summary.routing_patch_num_map) { + dr_json["routing_patch_num_map"][std::to_string(routing_layer_idx)] = patch_num; + } + dr_json["total_patch_num"] = dr_summary.total_patch_num; + for (auto& [routing_layer_idx, violation_num] : dr_summary.routing_violation_num_map) { + dr_json["routing_violation_num_map"][std::to_string(routing_layer_idx)] = violation_num; + } + dr_json["total_violation_num"] = dr_summary.total_violation_num; + for (auto& [clock_name, timing] : dr_summary.clock_timing_map) { + dr_json["clock_timing_map"]["clock_name"] = clock_name; + dr_json["clock_timing_map"]["timing"] = timing; + } + for (auto& [type, power] : dr_summary.type_power_map) { + dr_json["type_power_map"]["type"] = type; + dr_json["type_power_map"]["power"] = power; + } + dr_json_list.push_back(dr_json); + } + json_rt["DR"] = dr_json_list; } - for (int i = 0; i < (int) rt_sum.la_summary.clocks_timing.size(); i++) { - auto clock_timing = rt_sum.la_summary.clocks_timing[i]; - json_er["clocks_timing"][i]["clock_name"] = clock_timing.clock_name; - json_er["clocks_timing"][i]["setup_tns"] = clock_timing.setup_tns; - json_er["clocks_timing"][i]["setup_wns"] = clock_timing.setup_wns; - json_er["clocks_timing"][i]["suggest_freq"] = clock_timing.suggest_freq; - } - json_er["static_power"] = rt_sum.la_summary.power_info.static_power; - json_er["dynamic_power"] = rt_sum.la_summary.power_info.dynamic_power; - - json_rt["ER"] = json_er; - - // GR - json json_gr_list; - for (auto [id, gr_sum] : rt_sum.iter_gr_summary_map) { - json json_gr; - json_gr["total_demand"] = gr_sum.total_demand; - for (auto demand : gr_sum.routing_demand_map) { - json_gr["routing_demand_map"][std::to_string(demand.first)] = demand.second; + { + // VRSummary + json vr_json; + for (auto& [routing_layer_idx, wire_length] : summary_irt.vr_summary.routing_wire_length_map) { + vr_json["routing_wire_length_map"][std::to_string(routing_layer_idx)] = wire_length; } - - json_gr["total_overflow"] = gr_sum.total_overflow; - for (auto routing_overflow : gr_sum.routing_overflow_map) { - json_gr["routing_overflow_map"][std::to_string(routing_overflow.first)] = routing_overflow.second; + vr_json["total_wire_length"] = summary_irt.vr_summary.total_wire_length; + for (auto& [cut_layer_idx, via_num] : summary_irt.vr_summary.cut_via_num_map) { + vr_json["cut_via_num_map"][std::to_string(cut_layer_idx)] = via_num; } - - json_gr["total_wire_length"] = gr_sum.total_wire_length; - for (auto routing_wire_length : gr_sum.routing_wire_length_map) { - json_gr["routing_wire_length_map"][std::to_string(routing_wire_length.first)] = routing_wire_length.second; + vr_json["total_via_num"] = summary_irt.vr_summary.total_via_num; + for (auto& [routing_layer_idx, patch_num] : summary_irt.vr_summary.routing_patch_num_map) { + vr_json["routing_patch_num_map"][std::to_string(routing_layer_idx)] = patch_num; } - - json_gr["total_cut_via_num"] = gr_sum.total_via_num; - for (auto cut_via_num : gr_sum.cut_via_num_map) { - json_gr["cut_via_num_map"][std::to_string(cut_via_num.first)] = cut_via_num.second; + vr_json["total_patch_num"] = summary_irt.vr_summary.total_patch_num; + for (auto& [routing_layer_idx, violation_num] : summary_irt.vr_summary.within_net_routing_violation_num_map) { + vr_json["within_net_routing_violation_num_map"][std::to_string(routing_layer_idx)] = violation_num; } - - for (int i = 0; i < (int) gr_sum.clocks_timing.size(); i++) { - auto clock_timing = gr_sum.clocks_timing[i]; - json_gr["clocks_timing"][i]["clock_name"] = clock_timing.clock_name; - json_gr["clocks_timing"][i]["setup_tns"] = clock_timing.setup_tns; - json_gr["clocks_timing"][i]["setup_wns"] = clock_timing.setup_wns; - json_gr["clocks_timing"][i]["suggest_freq"] = clock_timing.suggest_freq; + vr_json["within_net_total_violation_num"] = summary_irt.vr_summary.within_net_total_violation_num; + for (auto& [routing_layer_idx, violation_num] : summary_irt.vr_summary.among_net_routing_violation_num_map) { + vr_json["among_net_routing_violation_num_map"][std::to_string(routing_layer_idx)] = violation_num; } - json_gr["static_power"] = gr_sum.power_info.static_power; - json_gr["dynamic_power"] = gr_sum.power_info.dynamic_power; - json_gr_list[std::to_string(id)] = json_gr; - } - json_rt["GR"] = json_gr_list; - - // TA - json json_ta; - // wirelength, violation - json_ta["total_wire_length"] = rt_sum.ta_summary.total_wire_length; - for (auto routing_wire_length : rt_sum.ta_summary.routing_wire_length_map) { - json_ta["routing_wire_length_map"][std::to_string(routing_wire_length.first)] = routing_wire_length.second; - } - - json_ta["total_violation_num"] = rt_sum.ta_summary.total_violation_num; - for (auto routing_violation : rt_sum.ta_summary.routing_violation_num_map) { - json_ta["routing_violation_num_map"][std::to_string(routing_violation.first)] = routing_violation.second; + vr_json["among_net_total_violation_num"] = summary_irt.vr_summary.among_net_total_violation_num; + for (auto& [clock_name, timing] : summary_irt.vr_summary.clock_timing_map) { + vr_json["clock_timing_map"]["clock_name"] = clock_name; + vr_json["clock_timing_map"]["timing"] = timing; + } + for (auto& [type, power] : summary_irt.vr_summary.type_power_map) { + vr_json["type_power_map"]["type"] = type; + vr_json["type_power_map"]["power"] = power; + } + json_rt["VR"] = vr_json; } - json_rt["TA"] = json_ta; - - // DR - json json_dr_list; - for (auto [id, dr_sum] : rt_sum.iter_dr_summary_map) { - json json_dr; - - json_dr["total_wire_length"] = dr_sum.total_wire_length; - for (auto routing_wire_length : dr_sum.routing_wire_length_map) { - json_dr["routing_wire_length_map"][std::to_string(routing_wire_length.first)] = routing_wire_length.second; + { + // ERSummary + json er_json; + for (auto& [routing_layer_idx, demand] : summary_irt.er_summary.routing_demand_map) { + er_json["routing_demand_map"][std::to_string(routing_layer_idx)] = demand; } - - json_dr["total_via_num"] = dr_sum.total_via_num; - for (auto cut_via_num : dr_sum.cut_via_num_map) { - json_dr["cut_via_num_map"][std::to_string(cut_via_num.first)] = cut_via_num.second; + er_json["total_demand"] = summary_irt.er_summary.total_demand; + for (auto& [routing_layer_idx, overflow] : summary_irt.er_summary.routing_overflow_map) { + er_json["routing_overflow_map"][std::to_string(routing_layer_idx)] = overflow; } - - json_dr["total_patch_num"] = dr_sum.total_patch_num; - for (auto routing_patch_num : dr_sum.routing_patch_num_map) { - json_dr["routing_patch_num_map"][std::to_string(routing_patch_num.first)] = routing_patch_num.second; + er_json["total_overflow"] = summary_irt.er_summary.total_overflow; + for (auto& [routing_layer_idx, wire_length] : summary_irt.er_summary.routing_wire_length_map) { + er_json["routing_wire_length_map"][std::to_string(routing_layer_idx)] = wire_length; } - - json_dr["total_violation_num"] = dr_sum.total_violation_num; - for (auto routing_violation : dr_sum.routing_violation_num_map) { - json_dr["routing_violation_num_map"][std::to_string(routing_violation.first)] = routing_violation.second; + er_json["total_wire_length"] = summary_irt.er_summary.total_wire_length; + for (auto& [cut_layer_idx, via_num] : summary_irt.er_summary.cut_via_num_map) { + er_json["cut_via_num_map"][std::to_string(cut_layer_idx)] = via_num; } - - for (int i = 0; i < (int) dr_sum.clocks_timing.size(); i++) { - auto clock_timing = dr_sum.clocks_timing[i]; - json_dr["clocks_timing"][i]["clock_name"] = clock_timing.clock_name; - json_dr["clocks_timing"][i]["setup_tns"] = clock_timing.setup_tns; - json_dr["clocks_timing"][i]["setup_wns"] = clock_timing.setup_wns; - json_dr["clocks_timing"][i]["suggest_freq"] = clock_timing.suggest_freq; + er_json["total_via_num"] = summary_irt.er_summary.total_via_num; + for (auto& [clock_name, timing] : summary_irt.er_summary.clock_timing_map) { + er_json["clock_timing_map"]["clock_name"] = clock_name; + er_json["clock_timing_map"]["timing"] = timing; } - json_dr["static_power"] = dr_sum.power_info.static_power; - json_dr["dynamic_power"] = dr_sum.power_info.dynamic_power; - json_dr_list[std::to_string(id)] = json_dr; + for (auto& [type, power] : summary_irt.er_summary.type_power_map) { + er_json["type_power_map"]["type"] = type; + er_json["type_power_map"]["power"] = power; + } + json_rt["ER"] = er_json; } - json_rt["DR"] = json_dr_list; - -#endif return json_rt; } @@ -252,32 +285,12 @@ json FeatureParser::buildSummaryPL(std::string step) if (step == "place") { summary_pl["gplace"]["place_density"] = pl_summary.gplace.place_density; - // summary_pl["gplace"]["pin_density"] = pl_summary.gplace.pin_density; - // summary_pl["gplace"]["HPWL"] = pl_summary.gplace.HPWL; - // summary_pl["gplace"]["STWL"] = pl_summary.gplace.STWL; - // summary_pl["gplace"]["GRWL"] = pl_summary.gplace.GRWL; - - // summary_pl["gplace"]["egr_tof"] = pl_summary.gplace.egr_tof; - // summary_pl["gplace"]["egr_mof"] = pl_summary.gplace.egr_mof; - // summary_pl["gplace"]["egr_ace"] = pl_summary.gplace.egr_ace; - - // summary_pl["gplace"]["tns"] = pl_summary.gplace.tns; - // summary_pl["gplace"]["wns"] = pl_summary.gplace.wns; - // summary_pl["gplace"]["suggest_freq"] = pl_summary.gplace.suggest_freq; + summary_pl["gplace"]["HPWL"] = pl_summary.gplace.HPWL; + summary_pl["gplace"]["STWL"] = pl_summary.gplace.STWL; summary_pl["dplace"]["place_density"] = pl_summary.dplace.place_density; - // summary_pl["dplace"]["pin_density"] = pl_summary.dplace.pin_density; - // summary_pl["dplace"]["HPWL"] = pl_summary.dplace.HPWL; - // summary_pl["dplace"]["STWL"] = pl_summary.dplace.STWL; - // summary_pl["dplace"]["GRWL"] = pl_summary.dplace.GRWL; - - // summary_pl["dplace"]["egr_tof"] = pl_summary.dplace.egr_tof; - // summary_pl["dplace"]["egr_mof"] = pl_summary.dplace.egr_mof; - // summary_pl["dplace"]["egr_ace"] = pl_summary.dplace.egr_ace; - - // summary_pl["dplace"]["tns"] = pl_summary.dplace.tns; - // summary_pl["dplace"]["wns"] = pl_summary.dplace.wns; - // summary_pl["dplace"]["suggest_freq"] = pl_summary.dplace.suggest_freq; + summary_pl["dplace"]["HPWL"] = pl_summary.dplace.HPWL; + summary_pl["dplace"]["STWL"] = pl_summary.dplace.STWL; summary_pl["instance_cnt"] = pl_summary.instance_cnt; summary_pl["fix_inst_cnt"] = pl_summary.fix_inst_cnt; @@ -291,22 +304,10 @@ json FeatureParser::buildSummaryPL(std::string step) } // 3: Data parameters required for legalization. else if (step == "legalization") { - summary_pl["legalization"]["place_density"] = pl_summary.lg_summary.pl_common_summary.place_density; - // summary_pl["legalization"]["pin_density"] = pl_summary.lg_summary.pl_common_summary.pin_density; - // summary_pl["legalization"]["HPWL"] = pl_summary.lg_summary.pl_common_summary.HPWL; - // summary_pl["legalization"]["STWL"] = pl_summary.lg_summary.pl_common_summary.STWL; - // summary_pl["legalization"]["GRWL"] = pl_summary.lg_summary.pl_common_summary.GRWL; - - // summary_pl["legalization"]["egr_tof"] = pl_summary.lg_summary.pl_common_summary.egr_tof; - // summary_pl["legalization"]["egr_mof"] = pl_summary.lg_summary.pl_common_summary.egr_mof; - // summary_pl["legalization"]["egr_ace"] = pl_summary.lg_summary.pl_common_summary.egr_ace; - - // summary_pl["legalization"]["tns"] = pl_summary.lg_summary.pl_common_summary.tns; - // summary_pl["legalization"]["wns"] = pl_summary.lg_summary.pl_common_summary.wns; - // summary_pl["legalization"]["suggest_freq"] = pl_summary.lg_summary.pl_common_summary.suggest_freq; - - summary_pl["legalization"]["total_movement"] = pl_summary.lg_summary.lg_total_movement; - summary_pl["legalization"]["max_movement"] = pl_summary.lg_summary.lg_max_movement; + summary_pl["HPWL"] = pl_summary.lg_summary.pl_common_summary.HPWL; + summary_pl["STWL"] = pl_summary.lg_summary.pl_common_summary.STWL; + summary_pl["total_movement"] = pl_summary.lg_summary.lg_total_movement; + summary_pl["max_movement"] = pl_summary.lg_summary.lg_max_movement; } return summary_pl; diff --git a/src/interface/gui/CMakeLists.txt b/src/interface/gui/CMakeLists.txt index a4be71629664afdaa1c64b28fcef8780f19d4ead..b1d38a3fb9fd07b0029e8d8de070d8adf7155f8c 100644 --- a/src/interface/gui/CMakeLists.txt +++ b/src/interface/gui/CMakeLists.txt @@ -53,6 +53,7 @@ set(sources ${CMAKE_CURRENT_SOURCE_DIR}/src/guiDB/idbfastsetupclocktree.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/guiDB/idbfastsetupInstancedemo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/guiDB/idbfastsetupCellMaster.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/guiDB/idbfastsetupgraph.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/graphicsitem/guiitem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/graphicsitem/guirect.cpp @@ -191,6 +192,7 @@ target_link_libraries(iGUI file_manager_placement tool_api_ipl ieda_feature + ivec_db ) if(OpenMP_CXX_FOUND) target_link_libraries(iGUI diff --git a/src/interface/gui/include/guigraphicsscene.h b/src/interface/gui/include/guigraphicsscene.h index 02d4b0520260ffb88ebc26e2458b5d252ed2502c..ef1d4c6e4fe49cce1b24fcb82c1d2839d096bb70 100644 --- a/src/interface/gui/include/guigraphicsscene.h +++ b/src/interface/gui/include/guigraphicsscene.h @@ -23,6 +23,7 @@ #include "guidatabase.h" // #include "guidbinterface.h" #include +#include #include "builder.h" #include "file_cts.h" @@ -33,6 +34,7 @@ #include "line.h" #include "ruler.h" #include "shape.h" +#include "vec_net.h" class DbSetup; @@ -63,6 +65,7 @@ class GuiGraphicsScene : public QGraphicsScene { void createDrc(std::map>& drc_db, int max_num = -1); void createClockTree(std::vector& node_list); void updateInstanceInFastMode(std::vector& file_inst_list); + void createGraph(std::map net_map); void onDbChanged(DbSetup* db_setup); void fitView(qreal width, qreal height); diff --git a/src/interface/gui/interface/gui_io.h b/src/interface/gui/interface/gui_io.h index f8ff0261e3008579e6e2f1755d3425e1b27c85ee..a66fecf93cc06e0b62e8de4cbb9485ebcfab8789 100644 --- a/src/interface/gui/interface/gui_io.h +++ b/src/interface/gui/interface/gui_io.h @@ -15,6 +15,7 @@ // See the Mulan PSL v2 for more details. // *************************************************************************************** #pragma once +#include #include #include @@ -22,6 +23,7 @@ #include "file_cts.h" #include "idrc_violation.h" #include "mainwindow.h" +#include "vec_net.h" #define guiInst (igui::GuiIO::getInstance()) using namespace idb; @@ -49,6 +51,7 @@ namespace igui { void readDB(IdbBuilder* _builder); void readDrcDb(std::map>& drc_db, int max_num = -1); void readClockTreeDb(std::vector& node_list); + void readGraphDb(std::map net_map); bool captureDesign(std::string path); diff --git a/src/interface/gui/interface/idb_io.cpp b/src/interface/gui/interface/idb_io.cpp index 600129531ff10e3d328e39f89ea4d7140167a67a..75d32b0a54132893a47c5405dbfeb07ffc2dd3aa 100644 --- a/src/interface/gui/interface/idb_io.cpp +++ b/src/interface/gui/interface/idb_io.cpp @@ -31,4 +31,6 @@ namespace igui { _gui_win->updateTree(); } + void GuiIO::readGraphDb(std::map net_map) { _gui_win->get_scene()->createGraph(net_map); } + } // namespace igui \ No newline at end of file diff --git a/src/interface/gui/src/guiDB/idbfastsetup.cpp b/src/interface/gui/src/guiDB/idbfastsetup.cpp index f6e6381c243ee74bda569eef2e4b2335186a35d5..ed5610b61eaa484c4eb2cfb812f87839c52abde9 100644 --- a/src/interface/gui/src/guiDB/idbfastsetup.cpp +++ b/src/interface/gui/src/guiDB/idbfastsetup.cpp @@ -220,8 +220,8 @@ void IdbSpeedUpSetup::createChip() { createCore(); createIO(); createRow(); - createInstance(); - createSpecialNet(); + // createInstance(); + // createSpecialNet(); createNet(); createTrackGrid(); createBlockage(); @@ -922,7 +922,11 @@ void IdbSpeedUpSetup::createNet() { // #pragma omp parallel for + int net_id = 0; for (IdbNet* net : net_list->get_net_list()) { + // if ("FE_OFN5472_FE_OFN426_n686" != net->get_net_name()) { + // continue; + // } GuiSpeedupItemType gui_type = getNetGuiType(net); for (IdbRegularWire* wire : net->get_wire_list()->get_wire_list()) { diff --git a/src/interface/gui/src/guiDB/idbfastsetup.h b/src/interface/gui/src/guiDB/idbfastsetup.h index e4cce191e523412efc18d7186a4b58257307dbb0..7cf2b52700e856e46414ef48b6b29b1f8729d284 100644 --- a/src/interface/gui/src/guiDB/idbfastsetup.h +++ b/src/interface/gui/src/guiDB/idbfastsetup.h @@ -46,6 +46,7 @@ #include "idrc_violation.h" #include "lef_service.h" #include "transform.h" +#include "vec_net.h" using namespace idb; @@ -76,6 +77,8 @@ class IdbSpeedUpSetup : public DbSetup { /// drc void showDrc(std::map>& drc_db, int max_num = -1); + void showGraph(std::map net_map); + /// clock tree void showClockTree(std::vector& _node_list); GuiSpeedupClockTreeItem* buildNodeItem(iplf::CtsTreeNode* clk_node, QPointF pt, qreal unit_step); diff --git a/src/interface/gui/src/guiDB/idbfastsetupdrc.cpp b/src/interface/gui/src/guiDB/idbfastsetupdrc.cpp index 8017792416b3786d7a340d1eabd64dea422c7a77..33830d5c0b872d664d079eb164f04d8293f13d90 100644 --- a/src/interface/gui/src/guiDB/idbfastsetupdrc.cpp +++ b/src/interface/gui/src/guiDB/idbfastsetupdrc.cpp @@ -97,4 +97,4 @@ void IdbSpeedUpSetup::createDrc(GuiSpeedupDrcList* drc_list, idrc::DrcViolation* } item->add_rect(rect); } -} \ No newline at end of file +} diff --git a/src/interface/gui/src/guiDB/idbfastsetupgraph.cpp b/src/interface/gui/src/guiDB/idbfastsetupgraph.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8150737f7458ceffa58953cb6c9d25c31c4677f6 --- /dev/null +++ b/src/interface/gui/src/guiDB/idbfastsetupgraph.cpp @@ -0,0 +1,107 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#include "guiConfig.h" +#include "idbfastsetup.h" +#include "omp.h" +/// this is hord code for debug graph +void IdbSpeedUpSetup::showGraph(std::map net_map) { + std::cout << "begin show graph" << std::endl; + for (auto [net_id, net] : net_map) { + auto container = _gui_design->get_drc_container("Metal Short"); + if (container != nullptr) { + for (auto wire : net.get_wires()) { + auto& [node1, node2] = wire.get_connected_nodes(); + if (node1 == nullptr && node2 == nullptr) { + std::cout << "error node...." << std::endl; + continue; + } + + std::string layer1 = "M" + std::to_string(node1->get_layer_id() / 2 + 1); + auto drc_list1 = container->findDrcList(layer1); + if (drc_list1 == nullptr) { + std::cout << "error drc_list1...." << layer1 << std::endl; + continue; + } + + QRectF rect1 = + _transform.db_to_guidb_rect(node1->get_x() - 20, node1->get_y() - 20, node1->get_x() + 20, node1->get_y() + 20); + GuiSpeedupDrc* item1 = drc_list1->findItem(rect1.center()); + if (item1 == nullptr) { + return; + } + item1->add_rect(rect1); + + std::string layer2 = "M" + std::to_string(node2->get_layer_id() / 2 + 1); + auto drc_list2 = container->findDrcList(layer2); + if (drc_list2 == nullptr) { + std::cout << "error drc_list2...." << std::endl; + continue; + } + + int detal = 20; + QRectF rect2 = _transform.db_to_guidb_rect(node2->get_x() - detal, node2->get_y() - detal, node2->get_x() + detal, + node2->get_y() + detal); + GuiSpeedupDrc* item2 = drc_list2->findItem(rect2.center()); + if (item2 == nullptr) { + return; + } + item2->add_rect(rect2); + + for (auto& [path_node1, path_node2] : wire.get_paths()) { + if (path_node1 == nullptr && path_node2 == nullptr) { + std::cout << "error node...." << std::endl; + continue; + } + std::string layer_path1 = "M" + std::to_string(path_node1->get_layer_id() / 2 + 1); + std::string layer_path2 = "M" + std::to_string(path_node2->get_layer_id() / 2 + 1); + if (layer_path1 != layer_path2) { + continue; + } + + int llx = std::min(path_node1->get_x(), path_node2->get_x()); + int lly = std::min(path_node1->get_y(), path_node2->get_y()); + int urx = std::max(path_node1->get_x(), path_node2->get_x()); + int ury = std::max(path_node1->get_y(), path_node2->get_y()); + + auto path_list = container->findDrcList(layer_path1); + if (path_list == nullptr) { + std::cout << "error path_list...." << std::endl; + continue; + } + + /// horizontal + if (lly == ury) { + lly -= 3; + ury += 3; + } else { + llx -= 3; + urx += 3; + } + QRectF rect_path = _transform.db_to_guidb_rect(llx, lly, urx, ury); + GuiSpeedupDrc* item_path = path_list->findItem(rect_path.center()); + if (item_path == nullptr) { + std::cout << "error item_path...." << std::endl; + continue; + } + + item_path->add_rect(rect_path); + } + } + } + } + std::cout << "end show graph" << std::endl; +} \ No newline at end of file diff --git a/src/interface/gui/src/guigraphicsscene.cpp b/src/interface/gui/src/guigraphicsscene.cpp index b789bd8b31c8968794fb87adb93292598bbe92b4..ec0590cb214f500c1a3f971f4eee0077234d5b28 100644 --- a/src/interface/gui/src/guigraphicsscene.cpp +++ b/src/interface/gui/src/guigraphicsscene.cpp @@ -160,6 +160,10 @@ void GuiGraphicsScene::createDrc(std::mapshowDrc(drc_db, max_num); } +void GuiGraphicsScene::createGraph(std::map net_map) { + ((IdbSpeedUpSetup*)_db_setup)->showGraph(net_map); +} + void GuiGraphicsScene::createClockTree(std::vector& node_list) { ((IdbSpeedUpSetup*)_db_setup)->showClockTree(node_list); } diff --git a/src/interface/gui/src/guispeedupitems/guispeedupdrc.h b/src/interface/gui/src/guispeedupitems/guispeedupdrc.h index 055d5f396221b75363c902e0753b3c48b4b06119..50ac0338b2f4fe9c93d0bffeab45f57bf8270e31 100644 --- a/src/interface/gui/src/guispeedupitems/guispeedupdrc.h +++ b/src/interface/gui/src/guispeedupitems/guispeedupdrc.h @@ -41,8 +41,8 @@ class GuiSpeedupDrc : public GuiSpeedupItem { explicit GuiSpeedupDrc(int32_t z_order, GuiSpeedupItem* parent = nullptr, GuiSpeedupItemType type = GuiSpeedupItemType::kNone) : GuiSpeedupItem(parent, type) { - setPen(QColor(255, 0, 0)); - setBrush(QBrush(QColor(255, 0, 0), Qt::BrushStyle::NoBrush)); + setPen(QColor(255, 255, 255)); + setBrush(QBrush(QColor(255, 255, 255), Qt::BrushStyle::SolidPattern)); _brush = brush(); _pen = pen(); setZValue(100); diff --git a/src/interface/mcp-iEDA/Dockerfile b/src/interface/mcp-iEDA/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..75eb276a9c84032dd0d8e7adca0188774f2dedb3 --- /dev/null +++ b/src/interface/mcp-iEDA/Dockerfile @@ -0,0 +1,41 @@ + +FROM docker.cnb.cool/ecoslab/rtl2gds/ieda:latest AS builder +RUN bash build.sh + +FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS uv + +# Install the project into `/app` +WORKDIR /app + +# Enable bytecode compilation +ENV UV_COMPILE_BYTECODE=1 + +# Copy from the cache instead of linking since it's a mounted volume +ENV UV_LINK_MODE=copy + +# Install the project's dependencies using the lockfile and settings +RUN --mount=type=cache,target=/root/.cache/uv \ + --mount=type=bind,source=uv.lock,target=uv.lock \ + --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ + uv sync --frozen --no-install-project --no-dev --no-editable + +# Then, add the rest of the project source code and install it +# Installing separately from its dependencies allows optimal layer caching +ADD . /app +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --frozen --no-dev --no-editable + +COPY --from=builder /opt/iEDA /app/iEDA + +ENV iEDA=/app/iEDA/bin/iEDA +ENV MCP_SERVER_TYPE=stdio +ENV MCP_SERVER_URL=0.0.0.0 +ENV MCP_SERVER_PORT=3002 + +ENV WORKSPACE=/app/iEDA/scripts/design/sky130_gcd + +# Place executables in the environment at the front of the path +ENV PATH="/app/iEDA/bin:/app/.venv/bin:$PATH" + +# CMD ["iEDA", "-v"] +ENTRYPOINT ["mcp-iEDA"] \ No newline at end of file diff --git a/src/interface/mcp-iEDA/LICENSE b/src/interface/mcp-iEDA/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..d1e8feaac9c8e7815c1d32857faf9a17d22e16d9 --- /dev/null +++ b/src/interface/mcp-iEDA/LICENSE @@ -0,0 +1,146 @@ +# *************************************************************************************** +# Copyright (c) 2023-2025 Peng Cheng Laboratory +# Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +# Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +# +# iEDA is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +# +# See the Mulan PSL v2 for more details. +# *************************************************************************************** + + 木兰宽松许可证, 第2版 + + 木兰宽松许可证, 第2版 + 2020年1月 http://license.coscl.org.cn/MulanPSL2 + + Copyright (c) [2023-2026] [鹏城实验室, 中科院计算所, 北京开源芯片研究院] + + + 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: + + 0. 定义 + + “软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 + + “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 + + “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 + + “法人实体”是指提交贡献的机构及其“关联实体”。 + + “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 + + 1. 授予版权许可 + + 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 + + 2. 授予专利许可 + + 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 + + 3. 无商标许可 + + “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 + + 4. 分发限制 + + 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 + + 5. 免责声明与责任限制 + + “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 + + 6. 语言 + “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 + + 条款结束 + + 如何将木兰宽松许可证,第2版,应用到您的软件 + + 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: + + 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; + + 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; + + 3, 请将如下声明文本放入每个源文件的头部注释中。 + + Copyright (c) [2023-2026] [Peng Cheng Laboratary, Institute of Computing Technology CAS, Beijing Institute of Open Source Chip] + [Software Name] is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. + + + Mulan Permissive Software License,Version 2 + + Mulan Permissive Software License,Version 2 (Mulan PSL v2) + January 2020 http://license.coscl.org.cn/MulanPSL2 + + Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: + + 0. Definition + + Software means the program and related documents which are licensed under this License and comprise all Contribution(s). + + Contribution means the copyrightable work licensed by a particular Contributor under this License. + + Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. + + Legal Entity means the entity making a Contribution and all its Affiliates. + + Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. + + 1. Grant of Copyright License + + Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. + + 2. Grant of Patent License + + Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. + + 3. No Trademark License + + No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. + + 4. Distribution Restriction + + You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. + + 5. Disclaimer of Warranty and Limitation of Liability + + THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 6. Language + + THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. + + END OF THE TERMS AND CONDITIONS + + How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software + + To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: + + i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; + + ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package; + + iii Attach the statement to the appropriate annotated syntax at the beginning of each source file. + + + Copyright (c) [2023-2026] [Peng Cheng Laboratary, Institute of Computing Technology, Beijing Institute of Open Source Chip] + [Software Name] is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. diff --git a/src/interface/mcp-iEDA/README.md b/src/interface/mcp-iEDA/README.md index a7d87af86fd236b55fb9fd40ce9612da4faa29a8..062343163b560542d29924b953e0c6dc7a5b6157 100644 --- a/src/interface/mcp-iEDA/README.md +++ b/src/interface/mcp-iEDA/README.md @@ -1,3 +1,13 @@ +## Build + +Docker build: + +```bash +cd src/interface/mcp-iEDA +docker build -t mcp-ieda:1.0 . +``` +you can modify the Dockerfile to suit your needs, such as change MCP_SERVER_TYPE to "stdio" or "sse". If you want to use "sse" mode, you need config mcp server use mcp-ieda-sse method below. + ## Installation ### Using PIP @@ -14,21 +24,56 @@ python -m mcp_ieda ## Configuration ### Usage with VS Code you can add it to a file called `.vscode/mcp.json` in your workspace. The github Copilot extension will automatically detect and use this configuration.The iEDA Path need to be set in the environment variable. +
+Using pip installation ```json -{ - "servers": { - "mcp-ieda": { - "type": "stdio", - "command": "python", - "args": [ - "-m", - "mcp_ieda" - ], - "env": { - "iEDA": "${workspaceFolder}/scripts/design/sky130_gcd/iEDA", - } +"mcpServers": { + "mcp-ieda": { + "type": "stdio", + "command": "python", + "args": [ + "-m", + "mcp_ieda" + ], + "env": { + "iEDA": "${workspaceFolder}/scripts/design/sky130_gcd/iEDA", + "WORKSPACE":"${workspaceFolder}/scripts/design/sky130_gcd", + "MCP_SERVER_TYPE":"stdio" } + }, + "mcp-ieda-sse": { + "type": "sse", + "url": "http://localhost:3002/sse" } } -``` \ No newline at end of file +``` +
+ +
+Using docker + +```json +"mcpServers": { + "mcp-ieda": { + "command": "docker", + "args": [ + "run", + "-p", + "3002:3002", + "-v", + "/lib/x86_64-linux-gnu/libgomp.so.1:/lib/x86_64-linux-gnu/libgomp.so.1", + "-v", + "/lib/x86_64-linux-gnu/libunwind.so.8:/lib/x86_64-linux-gnu/libunwind.so.8", + "--rm", + "-i", + "mcp-ieda:1.0" + ] + } +} +``` +
+ +## Example +If you config mcp server as above, you can run mcp server by prompt in VSCode Copilot on Agent mode : "run iEDA example gcd". + diff --git a/src/interface/mcp-iEDA/pyproject.toml b/src/interface/mcp-iEDA/pyproject.toml index be8df87ee017613bea3601f4bf50504024eec7e5..3167fd729d17ec435a96940cf8e9f3b052d2ab1d 100644 --- a/src/interface/mcp-iEDA/pyproject.toml +++ b/src/interface/mcp-iEDA/pyproject.toml @@ -1,3 +1,4 @@ + [project] name = "mcp-iEDA" version = "0.1.0" @@ -9,7 +10,8 @@ license = { text = "Mulan PSL v2" } readme = "README.md" requires-python = ">=3.12" dependencies = [ - "mcp[cli]" + "mcp[cli]", + "python-dotenv" ] [project.scripts] diff --git a/src/interface/mcp-iEDA/src/mcp_ieda/.env b/src/interface/mcp-iEDA/src/mcp_ieda/.env new file mode 100644 index 0000000000000000000000000000000000000000..cdd50afd36529c5696e3767fb66652cb730125cc --- /dev/null +++ b/src/interface/mcp-iEDA/src/mcp_ieda/.env @@ -0,0 +1,7 @@ +# Environment variables + +iEDA=/home/taosimin/iEDA24/iEDA/scripts/28nm/t28/iEDA + +MCP_SERVER_TYPE=sse +MCP_SERVER_URL=192.168.224.167 +MCP_SERVER_PORT=3002 \ No newline at end of file diff --git a/src/interface/mcp-iEDA/src/mcp_ieda/__init__.py b/src/interface/mcp-iEDA/src/mcp_ieda/__init__.py index 08a977f22906e756c59349c2f970fa1de190dec5..241108cec8c13f2463166d756d9536f2ffcc4254 100644 --- a/src/interface/mcp-iEDA/src/mcp_ieda/__init__.py +++ b/src/interface/mcp-iEDA/src/mcp_ieda/__init__.py @@ -4,13 +4,23 @@ import sys import os from .server import serve +from dotenv import load_dotenv +load_dotenv() + def get_ieda_path() -> Path: - ieda_path = os.getenv('iEDA') + ieda_path = os.getenv("iEDA") if not ieda_path: raise EnvironmentError("Environment variable 'iEDA' is not set.") return Path(ieda_path) -def main(iEDA: Path | None, verbose: int) -> None: +def get_server_type() -> str: + server_type = os.getenv("MCP_SERVER_TYPE", "stdio") + if server_type not in ["stdio", "sse"]: + raise ValueError(f"Invalid MCP_SERVER_TYPE: {server_type}. Must be 'stdio' or 'sse'.") + return server_type + + +def main(iEDA: Path | None = None, verbose: int = 2) -> None: import asyncio logging_level = logging.WARN @@ -19,8 +29,22 @@ def main(iEDA: Path | None, verbose: int) -> None: elif verbose >= 2: logging_level = logging.DEBUG - logging.basicConfig(level=logging_level, stream=sys.stderr) - asyncio.run(serve(iEDA)) + logging.basicConfig( + level=logging_level, + stream=sys.stderr, + format="%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s", + ) + + if iEDA is None: + iEDA = get_ieda_path() + + logging.info(f"iEDA path: {iEDA}") + + server_type = get_server_type() + logging.info(f"Server type: {server_type}") + + serve(iEDA, server_type) + if __name__ == "__main__": try: @@ -29,5 +53,5 @@ if __name__ == "__main__": except EnvironmentError as e: ieda_path = None print(e) - - main(ieda_path, verbose=2) \ No newline at end of file + + main(ieda_path, verbose=2) diff --git a/src/interface/mcp-iEDA/src/mcp_ieda/__main__.py b/src/interface/mcp-iEDA/src/mcp_ieda/__main__.py index e1cbbfcec6a3c9da6c189026af1a22eab84019be..c5b1cafc41200ae4241c552fd4b7c86b8bc15d40 100644 --- a/src/interface/mcp-iEDA/src/mcp_ieda/__main__.py +++ b/src/interface/mcp-iEDA/src/mcp_ieda/__main__.py @@ -4,7 +4,7 @@ from mcp_ieda import main, get_ieda_path try: ieda_path = get_ieda_path() - print(f"iEDA path: {ieda_path}") + print(f"iEDA env path: {ieda_path}") except EnvironmentError as e: ieda_path = None print(e) diff --git a/src/interface/mcp-iEDA/src/mcp_ieda/example/gcd/run_iEDA.tcl b/src/interface/mcp-iEDA/src/mcp_ieda/example/gcd/run_iEDA.tcl new file mode 100755 index 0000000000000000000000000000000000000000..698bb39820273c3d21626723cbf07afa40350187 --- /dev/null +++ b/src/interface/mcp-iEDA/src/mcp_ieda/example/gcd/run_iEDA.tcl @@ -0,0 +1,44 @@ + +# (fixed) iEDA setting +set ::env(CONFIG_DIR) $::env(WORKSPACE)/iEDA_config +set ::env(FOUNDRY_DIR) $::env(WORKSPACE)/../../foundry/sky130 +set ::env(RESULT_DIR) $::env(WORKSPACE)/result +set ::env(TCL_SCRIPT_DIR) $::env(WORKSPACE)/script + +# design files +set ::env(DESIGN_TOP) gcd +set ::env(NETLIST_FILE) $::env(WORKSPACE)/result/verilog/gcd.v +set ::env(SDC_FILE) $::env(FOUNDRY_DIR)/sdc/gcd.sdc +set ::env(SPEF_FILE) $::env(FOUNDRY_DIR)/spef/gcd.spef + +# floorplan setting +## gcd +set ::env(DIE_AREA) "0.0 0.0 149.96 150.128" +set ::env(CORE_AREA) "9.996 10.08 139.964 140.048" + +puts "execuate iFP script start" +exec -ignorestderr $::env(iEDA) -script "$::env(TCL_SCRIPT_DIR)/iFP_script/run_iFP.tcl" >@ stdout +puts "execuate iFP script finished" + +set pattern {s/\( [^+ ]*\) + NET +/\1 + NET\1 +/} +exec sed -i $pattern $::env(RESULT_DIR)/iFP_result.def + +set TCL_SCRIPTS "iNO_script/run_iNO_fix_fanout.tcl \ +iPL_script/run_iPL.tcl \ +iCTS_script/run_iCTS.tcl \ +iCTS_script/run_iCTS_STA.tcl \ +iTO_script/run_iTO_drv.tcl \ +iTO_script/run_iTO_drv_STA.tcl \ +iTO_script/run_iTO_hold.tcl \ +iTO_script/run_iTO_hold_STA.tcl \ +iPL_script/run_iPL_legalization.tcl \ +iRT_script/run_iRT.tcl \ +iRT_script/run_iRT_DRC.tcl \ +iPL_script/run_iPL_filler.tcl \ +DB_script/run_def_to_gds_text.tcl" + +foreach SCRIPT $TCL_SCRIPTS { + puts "execuate script $::env(TCL_SCRIPT_DIR)/${SCRIPT} start" + exec -ignorestderr $::env(iEDA) -script "$::env(TCL_SCRIPT_DIR)/${SCRIPT}" >@ stdout + puts "execuate script $::env(TCL_SCRIPT_DIR)/${SCRIPT} finished" +} diff --git a/src/interface/mcp-iEDA/src/mcp_ieda/server.py b/src/interface/mcp-iEDA/src/mcp_ieda/server.py index 456c1e3abeb2661e2adba33cb791c189a2aaa2d2..b1fb3e8b8a30d02e67b8ace2e0105180f9b77d4a 100644 --- a/src/interface/mcp-iEDA/src/mcp_ieda/server.py +++ b/src/interface/mcp-iEDA/src/mcp_ieda/server.py @@ -26,21 +26,47 @@ from pydantic import BaseModel from pathlib import Path +current_dir = os.path.split(os.path.abspath(__file__))[0] + class iEDARun(BaseModel): - script_path: str + script_path: str +class iEDARunExample(BaseModel): + example_name: str class iEDAMcpTools(str, Enum): """ iEDA MCP tools """ iEDA_RUN = "iEDA_RUN" + iEDA_RUN_EXAMPLE = "iEDA_RUN_EXAMPLE" def run_ieda(iEDA: Path, script_path: str): - os.system(f"{iEDA} -script {script_path}") - os.system(f"echo {iEDA} -script {script_path} finished") + """Run iEDA with the given script path.""" + + import subprocess + script = f"{iEDA} -script {script_path}" + + logging.info(f"Run iEDA with script: {script}") + + process = subprocess.run(script, shell=True, check=True) + if process.returncode != 0: + raise RuntimeError(f"Subprocess failed with return code {process.returncode}") + + +def get_server_url() -> str: + """ + Get the server URL from environment variable or default to 'http://localhost'. + """ + return os.getenv("MCP_SERVER_URL", "localhost") + +def get_server_port() -> int: + """ + Get the server port from environment variable or default to 3002. + """ + return int(os.getenv("MCP_SERVER_PORT", 3002)) -async def serve(iEDA: Path): +def serve(iEDA: Path, transport="stdio"): logger = logging.getLogger(__name__) server = Server("mcp-iEDA") @@ -48,7 +74,8 @@ async def serve(iEDA: Path): @server.list_tools() async def list_tools() -> list[Tool]: return [ - Tool(name=iEDAMcpTools.iEDA_RUN, description="Run iEDA with script", inputSchema=iEDARun.schema()) + Tool(name=iEDAMcpTools.iEDA_RUN, description="Run iEDA with script", inputSchema=iEDARun.schema()), + Tool(name=iEDAMcpTools.iEDA_RUN_EXAMPLE, description="Run iEDA example", inputSchema=iEDARunExample.schema()) ] @server.call_tool() @@ -60,11 +87,57 @@ async def serve(iEDA: Path): logger.info(f"Run iEDA with script: {script_path}") run_ieda(iEDA, script_path) return [TextContent(type="text", text=f"Run iEDA with script: {script_path} successfully")] + elif tool == iEDAMcpTools.iEDA_RUN_EXAMPLE: + example_name = arguments.get("example_name") + if not example_name: + raise ValueError("Missing 'example_name' in arguments") + logger.info(f"Run iEDA example: {example_name}") + example_script_path = f"{current_dir}/./example/{example_name}/run_iEDA.tcl" + if os.path.exists(example_script_path): + run_ieda(iEDA, example_script_path) + return [TextContent(type="text", text=f"Run iEDA example: {example_name} successfully")] + else: + return [TextContent(type="text", text=f"Example: {example_script_path} not found")] else: raise ValueError(f"Unknown tool: {tool}") options = server.create_initialization_options() - async with stdio_server() as (read_stream, write_stream): - await server.run(read_stream, write_stream, options, raise_exceptions=True) + + if transport == "sse": + from mcp.server.sse import SseServerTransport + from starlette.applications import Starlette + from starlette.routing import Mount, Route + + sse = SseServerTransport("/messages/") + + async def handle_sse(request): + async with sse.connect_sse( + request.scope, request.receive, request._send + ) as streams: + await server.run( + streams[0], streams[1], options + ) + + starlette_app = Starlette( + debug=True, + routes=[ + Route("/sse", endpoint=handle_sse), + Mount("/messages/", app=sse.handle_post_message), + ], + ) + + import uvicorn + + server_url = get_server_url() + server_port = get_server_port() + logger.info(f"Starting iEDA MCP server at {server_url}") + uvicorn.run(starlette_app, host=server_url, port=server_port) + else: + import anyio + async def arun(): + async with stdio_server() as (read_stream, write_stream): + await server.run(read_stream, write_stream, options, raise_exceptions=True) + + anyio.run(arun) diff --git a/src/interface/mcp-iEDA/test/test_mcp.py b/src/interface/mcp-iEDA/test/test_mcp.py new file mode 100644 index 0000000000000000000000000000000000000000..0e65fe503d256f66d5048a1b0b7a96b5a9244363 --- /dev/null +++ b/src/interface/mcp-iEDA/test/test_mcp.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +''' +@File : test_mcp.py +@Time : 2025/07/24 12:44:42 +@Author : simin tao +@Version : 1.0 +@Contact : taosm@pcl.ac.cn +@Desc : test mcp ieda. +''' + + +import unittest +import os +import sys + +current_dir = os.path.split(os.path.abspath(__file__))[0] +root_dir = current_dir.rsplit("/", 1)[0] + +sys.path.append(root_dir) + +os.environ["iEDA"] = "/home/taosimin/iEDA24/iEDA/scripts/design/sky130_gcd/iEDA" +os.environ["WORKSPACE"] = "/home/taosimin/iEDA24/iEDA/scripts/design/sky130_gcd" + +from src.mcp_ieda import get_ieda_path +from src.mcp_ieda.server import run_ieda + + +class TestRuniEDA(unittest.TestCase): + def test_run(self): + iEDA = get_ieda_path() + run_ieda(iEDA, current_dir + "../../example/gcd/run_iEDA.tcl") + + +if __name__ == "__main__": + suite = unittest.TestLoader().loadTestsFromTestCase(TestRuniEDA) + unittest.TextTestRunner(verbosity=2).run(suite) \ No newline at end of file diff --git a/src/interface/mcp-iEDA/uv.lock b/src/interface/mcp-iEDA/uv.lock index 6bb03b4e93dc52f884f480dc9ce84b0a5ce187ff..6e2db5d6a5180bf7f9b76ba7722660e96be67cfe 100644 --- a/src/interface/mcp-iEDA/uv.lock +++ b/src/interface/mcp-iEDA/uv.lock @@ -153,10 +153,14 @@ version = "0.1.0" source = { editable = "." } dependencies = [ { name = "mcp", extra = ["cli"] }, + { name = "python-dotenv" }, ] [package.metadata] -requires-dist = [{ name = "mcp", extras = ["cli"] }] +requires-dist = [ + { name = "mcp", extras = ["cli"] }, + { name = "python-dotenv" }, +] [[package]] name = "mdurl" diff --git a/src/interface/python/CMakeLists.txt b/src/interface/python/CMakeLists.txt index ff662562d80bd9f3d2d3b2925b99bbf2b378e122..14cbe740aee29b7c05b11c0ee1382b5db7a5e745 100644 --- a/src/interface/python/CMakeLists.txt +++ b/src/interface/python/CMakeLists.txt @@ -1,7 +1,7 @@ # add_subdirectory(${HOME_THIRDPARTY}/pybind11 binary_dir) - SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) + # DEFINE PYTHON MODULE & CMAKE TARGET pybind11_add_module(ieda_py) @@ -22,8 +22,11 @@ add_subdirectory(py_ito) add_subdirectory(py_report) add_subdirectory(py_feature) add_subdirectory(py_eval) -# ADD SOURCE FILES -#file(GLOB_RECURSE PYTHON_INTERFACE_SRC CONFIGURE_DEPENDS ./*.cpp ./*.cc) +add_subdirectory(py_vec) +add_subdirectory(py_ipnp) + +# ADD SOURCE FILES +# file(GLOB_RECURSE PYTHON_INTERFACE_SRC CONFIGURE_DEPENDS ./*.cpp ./*.cc) file(GLOB PYTHON_INTERFACE_SRC CONFIGURE_DEPENDS *.cpp .h) # SET SOURCE FILES @@ -31,24 +34,23 @@ target_sources(ieda_py PUBLIC ${PYTHON_INTERFACE_SRC}) target_link_libraries(ieda_py PRIVATE - py_idb - py_config - py_flow - py_icts - py_idrc - py_ifp - py_ino - py_inst - py_ipdn - py_ipl - py_irt - py_ista - py_ipw - py_ito - py_report - py_feature - py_eval + py_idb + py_config + py_flow + py_icts + py_idrc + py_ifp + py_ino + py_inst + py_ipdn + py_ipl + py_irt + py_ista + py_ipw + py_ito + py_report + py_feature + py_eval + py_vec + py_ipnp ) - - - diff --git a/src/interface/python/py_config/py_config.cpp b/src/interface/python/py_config/py_config.cpp index 2165a013d220493925009f652dee89aa9942de71..b54b0fffcd2eb4d8ce80019d72825f89f1e36697 100644 --- a/src/interface/python/py_config/py_config.cpp +++ b/src/interface/python/py_config/py_config.cpp @@ -29,7 +29,7 @@ bool flow_init(const std::string& flow_config) } bool db_init(const std::string& config_path, const std::string& tech_lef_path, const std::vector& lef_paths, - const std::string& def_path, const std::string& verilog_path, const std::string& output_path, + const std::string& def_path, const std::string& verilog_path, const std::string& output_path, const std::string& feature_path, const std::vector& lib_paths, const std::string& sdc_path) { idm::DataConfig& dm_config = dmInst->get_config(); @@ -60,6 +60,9 @@ bool db_init(const std::string& config_path, const std::string& tech_lef_path, c if (not sdc_path.empty()) { dm_config.set_sdc_path(sdc_path); } + if (not feature_path.empty()) { + dm_config.set_feature_path(feature_path); + } return true; } diff --git a/src/interface/python/py_config/py_config.h b/src/interface/python/py_config/py_config.h index 1829de9ba3f7a6812f4df04563a1f91c97a6483b..fd1657b5da6969aecb74c0bbaeb9b14bff9a54b9 100644 --- a/src/interface/python/py_config/py_config.h +++ b/src/interface/python/py_config/py_config.h @@ -23,6 +23,6 @@ namespace python_interface { bool flow_init(const std::string& flow_config); bool db_init(const std::string& config_path, const std::string& tech_lef_path, const std::vector& lef_paths, - const std::string& def_path, const std::string& verilog_path, const std::string& output_path, + const std::string& def_path, const std::string& verilog_path, const std::string& output_path, const std::string& feature_path, const std::vector& lib_paths, const std::string& sdc_path); } // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/py_config/py_register_config.h b/src/interface/python/py_config/py_register_config.h index 0391b65b463cafb5d0a85f9e8983a09445c9ae5c..c041da6f9294f849acfcfd8500b627439b3d8f33 100644 --- a/src/interface/python/py_config/py_register_config.h +++ b/src/interface/python/py_config/py_register_config.h @@ -31,6 +31,7 @@ void register_config(pybind11::module& m){ py::arg("def_path") = "", py::arg("verilog_path") = "", py::arg("output_path") = "", + py::arg("feature_path") = "", py::arg("lib_paths") = std::vector{}, py::arg("sdc_path") = "" ); diff --git a/src/interface/python/py_eval/CMakeLists.txt b/src/interface/python/py_eval/CMakeLists.txt index 5dd533c8ca5f0a9221d92d1005274dd4d4f56a9a..74ce84d3323fe09f0b5de1d61569f9df3261ff1e 100644 --- a/src/interface/python/py_eval/CMakeLists.txt +++ b/src/interface/python/py_eval/CMakeLists.txt @@ -13,5 +13,6 @@ target_link_libraries(py_eval ) target_include_directories(py_eval PUBLIC + ${EVAL_DATA} ${CMAKE_CURRENT_SOURCE_DIR} ) \ No newline at end of file diff --git a/src/interface/python/py_eval/py_eval.cpp b/src/interface/python/py_eval/py_eval.cpp index ed46c050218c9d9fbf5d3b8737c67de8724b2a21..3c91c8b7a65990832884869c72530b11c9242e59 100644 --- a/src/interface/python/py_eval/py_eval.cpp +++ b/src/interface/python/py_eval/py_eval.cpp @@ -26,99 +26,181 @@ using namespace ieval; namespace python_interface { // wirelength evaluation -void init_wirelength_eval() +ieval::TotalWLSummary total_wirelength() { + ieval::TotalWLSummary total_wirelength_summary = WIRELENGTH_API_INST->totalWL(); + + ieval::TotalWLSummary result; + result.HPWL = total_wirelength_summary.HPWL; + result.FLUTE = total_wirelength_summary.FLUTE; + result.HTree = total_wirelength_summary.HTree; + result.VTree = total_wirelength_summary.VTree; + result.GRWL = total_wirelength_summary.GRWL; + + return result; } -int64_t eval_total_wirelength(int wirelength_type) -{ - return 0; -} -// congestion evaluation -void init_cong_eval(int bin_cnt_x, int bin_cnt_y) +// density evaluation +ieval::DensityValue cell_density(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) { + ieval::DensityValue density_value = DENSITY_API_INST->cellDensity(bin_cnt_x, bin_cnt_y, save_path); + return density_value; } -void eval_macro_density() +ieval::DensityValue pin_density(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) { + ieval::DensityValue density_value = DENSITY_API_INST->pinDensity(bin_cnt_x, bin_cnt_y, save_path); + return density_value; } -void eval_macro_pin_density() +ieval::DensityValue net_density(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) { + ieval::DensityValue density_value = DENSITY_API_INST->netDensity(bin_cnt_x, bin_cnt_y, save_path); + return density_value; } -void eval_cell_pin_density() + +// congestion evaluation +ieval::CongestionValue rudy_congestion(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) { + ieval::CongestionValue congestion_value = CONGESTION_API_INST->rudyCongestion(bin_cnt_x, bin_cnt_y, save_path); + return congestion_value; } -void eval_macro_margin() +ieval::CongestionValue lut_rudy_congestion(int bin_cnt_x, int bin_cnt_y, const std::string& save_path) { + ieval::CongestionValue congestion_value = CONGESTION_API_INST->lutRudyCongestion(bin_cnt_x, bin_cnt_y, save_path); + return congestion_value; } -void eval_continuous_white_space() +ieval::CongestionValue egr_congestion(const std::string& save_path) { + ieval::CongestionValue congestion_value = CONGESTION_API_INST->egrCongestion(save_path); + return congestion_value; } -void eval_macro_channel(float die_size_ratio) + +// timing and power evaluation +ieval::TimingSummary timing_power_hpwl() { + TimingPower_API_INST->evalTiming("HPWL", false); + + std::map timing_summary = TimingPower_API_INST->evalDesign(); + ieval::TimingSummary hpwl_timing_eval_summary; + + auto hpwl_timing_summary = timing_summary.at("HPWL"); + + std::for_each(hpwl_timing_summary.clock_timings.begin(), hpwl_timing_summary.clock_timings.end(), + [&hpwl_timing_eval_summary](const auto& clock_timing) { + hpwl_timing_eval_summary.clock_timings.push_back({ + clock_timing.clock_name, + clock_timing.setup_tns, + clock_timing.setup_wns, + clock_timing.hold_tns, + clock_timing.hold_wns, + clock_timing.suggest_freq + }); + }); + + hpwl_timing_eval_summary.static_power = hpwl_timing_summary.static_power; + hpwl_timing_eval_summary.dynamic_power = hpwl_timing_summary.dynamic_power; + + return hpwl_timing_eval_summary; } -void eval_cell_hierarchy(const std::string& plot_path, int level, int forward) +ieval::TimingSummary timing_power_stwl() { + TimingPower_API_INST->evalTiming("FLUTE", false); + + std::map timing_summary = TimingPower_API_INST->evalDesign(); + ieval::TimingSummary stwl_timing_eval_summary; + + auto stwl_timing_summary = timing_summary.at("FLUTE"); + + std::for_each(stwl_timing_summary.clock_timings.begin(), stwl_timing_summary.clock_timings.end(), + [&stwl_timing_eval_summary](const auto& clock_timing) { + stwl_timing_eval_summary.clock_timings.push_back({ + clock_timing.clock_name, + clock_timing.setup_tns, + clock_timing.setup_wns, + clock_timing.hold_tns, + clock_timing.hold_wns, + clock_timing.suggest_freq + }); + }); + + stwl_timing_eval_summary.static_power = stwl_timing_summary.static_power; + stwl_timing_eval_summary.dynamic_power = stwl_timing_summary.dynamic_power; + + return stwl_timing_eval_summary; } -void eval_macro_hierarchy(const std::string& plot_path, int level, int forward) +ieval::TimingSummary timing_power_egr() { + TimingPower_API_INST->evalTiming("EGR", false); + + std::map timing_summary = TimingPower_API_INST->evalDesign(); + ieval::TimingSummary egr_timing_eval_summary; + + auto egr_timing_summary = timing_summary.at("EGR"); + + std::for_each(egr_timing_summary.clock_timings.begin(), egr_timing_summary.clock_timings.end(), + [&egr_timing_eval_summary](const auto& clock_timing) { + egr_timing_eval_summary.clock_timings.push_back({ + clock_timing.clock_name, + clock_timing.setup_tns, + clock_timing.setup_wns, + clock_timing.hold_tns, + clock_timing.hold_wns, + clock_timing.suggest_freq + }); + }); + + egr_timing_eval_summary.static_power = egr_timing_summary.static_power; + egr_timing_eval_summary.dynamic_power = egr_timing_summary.dynamic_power; + + return egr_timing_eval_summary; } -void eval_macro_connection(const std::string& plot_path, int level, int forward) +// other evaluation (TO BE DONE) +void eval_macro_margin() { } -void eval_macro_pin_connection(const std::string& plot_path, int level, int forward) +void eval_continuous_white_space() { } -void eval_macro_io_pin_connection(const std::string& plot_path, int level, int forward) +void eval_macro_channel(float die_size_ratio) { } -void eval_inst_density(int inst_status, int eval_flip_flop) +void eval_cell_hierarchy(const std::string& plot_path, int level, int forward) { } -void eval_pin_density(int inst_status, int level) +void eval_macro_hierarchy(const std::string& plot_path, int level, int forward) { } -void eval_rudy_cong(int rudy_type, int direction) +void eval_macro_connection(const std::string& plot_path, int level, int forward) { } -std::vector eval_overflow() +void eval_macro_pin_connection(const std::string& plot_path, int level, int forward) { - return {}; } -// timing evaluation -void init_timing_eval() +void eval_macro_io_pin_connection(const std::string& plot_path, int level, int forward) { - } -// plot API -void plot_bin_value(const std::string& plot_path, const std::string& file_name, int value_type) -{ -} -void plot_tile_value(const std::string& plot_path, const std::string& file_name) +std::vector eval_overflow() { - + return {}; } -void plot_flow_value(const std::string& plot_path, const std::string& file_name, const std::string& step, const std::string& value) -{ -} } // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/py_eval/py_eval.h b/src/interface/python/py_eval/py_eval.h index 1e627b5f23dd0887df3ede8779f7ca6d0b20b451..c4933e428b2eef0d69c3ef1305f50e06fbecd1e0 100644 --- a/src/interface/python/py_eval/py_eval.h +++ b/src/interface/python/py_eval/py_eval.h @@ -18,17 +18,35 @@ #include #include + +#include "wirelength_db.h" +#include "density_db.h" +#include "congestion_db.h" +#include "timing_db.hh" + namespace python_interface { // wirelength evaluation -void init_wirelength_eval(); -int64_t eval_total_wirelength(int wirelength_type); +ieval::TotalWLSummary total_wirelength(); + +// density evaluation +ieval::DensityValue cell_density(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); +ieval::DensityValue pin_density(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); +ieval::DensityValue net_density(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); // congestion evaluation -void init_cong_eval(int bin_cnt_x, int bin_cnt_y); -void eval_macro_density(); -void eval_macro_pin_density(); -void eval_cell_pin_density(); +ieval::CongestionValue rudy_congestion(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); +ieval::CongestionValue lut_rudy_congestion(int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = ""); +ieval::CongestionValue egr_congestion(const std::string& save_path = ""); + +// timing and power evaluation +ieval::TimingSummary timing_power_hpwl(); +ieval::TimingSummary timing_power_stwl(); +ieval::TimingSummary timing_power_egr(); + + + + void eval_macro_margin(); void eval_macro_channel(float die_size_ratio = 0.5); void eval_continuous_white_space(); @@ -38,17 +56,7 @@ void eval_macro_connection(const std::string& plot_path, int level = 1, int forw void eval_macro_pin_connection(const std::string& plot_path, int level = 1, int forward = 1); void eval_macro_io_pin_connection(const std::string& plot_path, int level = 1, int forward = 1); -void eval_inst_density(int inst_status, int eval_flip_flop = 0); -void eval_pin_density(int inst_status, int level = 0); -void eval_rudy_cong(int rudy_type, int direction); std::vector eval_overflow(); -// timing evaluation -void init_timing_eval(); - -// plot API -void plot_bin_value(const std::string& plot_path, const std::string& file_name, int value_type); -void plot_tile_value(const std::string& plot_path, const std::string& file_name); -void plot_flow_value(const std::string& plot_path, const std::string& file_name, const std::string& step, const std::string& value); } // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/py_eval/py_register_eval.h b/src/interface/python/py_eval/py_register_eval.h index 05810d933a272d6ba40da90164f5aa5a6127884b..3173d41ff172a8fd599f6a66dfcd741a7476d2ac 100644 --- a/src/interface/python/py_eval/py_register_eval.h +++ b/src/interface/python/py_eval/py_register_eval.h @@ -21,18 +21,149 @@ #include "py_eval.h" namespace python_interface { + namespace py = pybind11; void register_eval(py::module& m) { // wirelength evaluation - m.def("init_wirelength_eval", init_wirelength_eval); - m.def("eval_total_wirelength", eval_total_wirelength, py::arg("wirelength_type")); + py::class_(m, "TotalWLSummary") + .def_readwrite("HPWL", &ieval::TotalWLSummary::HPWL) + .def_readwrite("FLUTE", &ieval::TotalWLSummary::FLUTE) + .def_readwrite("HTree", &ieval::TotalWLSummary::HTree) + .def_readwrite("VTree", &ieval::TotalWLSummary::VTree) + .def_readwrite("GRWL", &ieval::TotalWLSummary::GRWL); + + m.def("total_wirelength_dict", []() -> py::dict { + ieval::TotalWLSummary summary = total_wirelength(); + py::dict result; + result["1"] = summary.HPWL; + result["2"] = summary.FLUTE; + result["3"] = summary.HTree; + result["4"] = summary.VTree; + result["5"] = summary.GRWL; + return result; + }); + + + // density evaluation functions + m.def("cell_density", [](int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = "") -> py::tuple { + auto [max_density, avg_density] = cell_density(bin_cnt_x, bin_cnt_y, save_path); + return py::make_tuple(max_density, avg_density); + }, py::arg("bin_cnt_x") = 256, py::arg("bin_cnt_y") = 256, py::arg("save_path") = ""); + + m.def("pin_density", [](int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = "") -> py::tuple { + auto [max_density, avg_density] = pin_density(bin_cnt_x, bin_cnt_y, save_path); + return py::make_tuple(max_density, avg_density); + }, py::arg("bin_cnt_x") = 256, py::arg("bin_cnt_y") = 256, py::arg("save_path") = ""); + + m.def("net_density", [](int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = "") -> py::tuple { + auto [max_density, avg_density] = net_density(bin_cnt_x, bin_cnt_y, save_path); + return py::make_tuple(max_density, avg_density); + }, py::arg("bin_cnt_x") = 256, py::arg("bin_cnt_y") = 256, py::arg("save_path") = ""); + // congestion evalation - m.def("init_cong_eval", init_cong_eval, py::arg("bin_cnt_x"), py::arg("bin_cnt_y")); - m.def("eval_macro_density", eval_macro_density); - m.def("eval_macro_pin_density", eval_macro_pin_density); - m.def("eval_cell_pin_density", eval_cell_pin_density); + m.def("rudy_congestion", [](int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = "") -> py::tuple { + auto [max_congestion, total_congestion] = rudy_congestion(bin_cnt_x, bin_cnt_y, save_path); + return py::make_tuple(max_congestion, total_congestion); + }, py::arg("bin_cnt_x") = 256, py::arg("bin_cnt_y") = 256, py::arg("save_path") = ""); + + m.def("lut_rudy_congestion", [](int bin_cnt_x = 256, int bin_cnt_y = 256, const std::string& save_path = "") -> py::tuple { + auto [max_congestion, total_congestion] = lut_rudy_congestion(bin_cnt_x, bin_cnt_y, save_path); + return py::make_tuple(max_congestion, total_congestion); + }, py::arg("bin_cnt_x") = 256, py::arg("bin_cnt_y") = 256, py::arg("save_path") = ""); + + m.def("egr_congestion", [](const std::string& save_path = "") -> py::tuple { + auto [max_congestion, total_congestion] = egr_congestion(save_path); + return py::make_tuple(max_congestion, total_congestion); + }, py::arg("save_path") = ""); + + + // timing and power evaluation + py::class_(m, "ClockTiming") + .def_readwrite("clock_name", &ieval::ClockTiming::clock_name) + .def_readwrite("setup_wns", &ieval::ClockTiming::setup_wns) + .def_readwrite("setup_tns", &ieval::ClockTiming::setup_tns) + .def_readwrite("hold_wns", &ieval::ClockTiming::hold_wns) + .def_readwrite("hold_tns", &ieval::ClockTiming::hold_tns) + .def_readwrite("suggest_freq", &ieval::ClockTiming::suggest_freq); + + py::class_(m, "TimingSummary") + .def_readwrite("clock_timings", &ieval::TimingSummary::clock_timings) + .def_readwrite("static_power", &ieval::TimingSummary::static_power) + .def_readwrite("dynamic_power", &ieval::TimingSummary::dynamic_power); + + m.def("timing_power_hpwl", []() -> py::dict { + ieval::TimingSummary summary = timing_power_hpwl(); + py::dict result; + + py::list clock_list; + for (const auto& clock : summary.clock_timings) { + py::dict clock_dict; + clock_dict["clock_name"] = clock.clock_name; + clock_dict["setup_wns"] = clock.setup_wns; + clock_dict["setup_tns"] = clock.setup_tns; + clock_dict["hold_wns"] = clock.hold_wns; + clock_dict["hold_tns"] = clock.hold_tns; + clock_dict["suggest_freq"] = clock.suggest_freq; + clock_list.append(clock_dict); + } + result["clock_timings"] = clock_list; + + result["static_power"] = summary.static_power; + result["dynamic_power"] = summary.dynamic_power; + + return result; + }); + + m.def("timing_power_stwl", []() -> py::dict { + ieval::TimingSummary summary = timing_power_stwl(); + py::dict result; + + py::list clock_list; + for (const auto& clock : summary.clock_timings) { + py::dict clock_dict; + clock_dict["clock_name"] = clock.clock_name; + clock_dict["setup_wns"] = clock.setup_wns; + clock_dict["setup_tns"] = clock.setup_tns; + clock_dict["hold_wns"] = clock.hold_wns; + clock_dict["hold_tns"] = clock.hold_tns; + clock_dict["suggest_freq"] = clock.suggest_freq; + clock_list.append(clock_dict); + } + result["clock_timings"] = clock_list; + + result["static_power"] = summary.static_power; + result["dynamic_power"] = summary.dynamic_power; + + return result; + }); + + m.def("timing_power_egr", []() -> py::dict { + ieval::TimingSummary summary = timing_power_egr(); + py::dict result; + + py::list clock_list; + for (const auto& clock : summary.clock_timings) { + py::dict clock_dict; + clock_dict["clock_name"] = clock.clock_name; + clock_dict["setup_wns"] = clock.setup_wns; + clock_dict["setup_tns"] = clock.setup_tns; + clock_dict["hold_wns"] = clock.hold_wns; + clock_dict["hold_tns"] = clock.hold_tns; + clock_dict["suggest_freq"] = clock.suggest_freq; + clock_list.append(clock_dict); + } + result["clock_timings"] = clock_list; + + result["static_power"] = summary.static_power; + result["dynamic_power"] = summary.dynamic_power; + + return result; + }); + + + // other evaluation (TO BE DONE) m.def("eval_macro_margin", eval_macro_margin); m.def("eval_continuous_white_space", eval_continuous_white_space); m.def("eval_macro_channel", eval_macro_channel, py::arg("die_size_ratio")); @@ -42,36 +173,9 @@ void register_eval(py::module& m) m.def("eval_macro_pin_connection", eval_macro_pin_connection, py::arg("plot_path"), py::arg("level"), py::arg("forward")); m.def("eval_macro_io_pin_connection", eval_macro_io_pin_connection, py::arg("plot_path"), py::arg("level"), py::arg("forward")); - m.def("eval_inst_density", eval_inst_density, py::arg("inst_status"), py::arg("eval_flip_flop")); - m.def("eval_pin_density", eval_pin_density, py::arg("inst_status"), py::arg("level")); - m.def("eval_rudy_cong", eval_rudy_cong, py::arg("rudy_type"), py::arg("direction")); m.def("eval_overflow", eval_overflow); - // timing evaluation - m.def("init_timing_eval", init_timing_eval); - - // plot api - m.def("plot_bin_value", plot_bin_value, py::arg("plot_path"), py::arg("file_name"), py::arg("value_type")); - m.def("plot_tile_value", plot_tile_value, py::arg("plot_path"), py::arg("file_name")); - m.def("plot_flow_value", plot_flow_value, py::arg("plot_path"), py::arg("file_name"), py::arg("step"), py::arg("value")); - // m.def("eval_net_density", eval_net_density, py::arg("inst_status")); - // m.def("eval_local_net_density", eval_local_net_density); - // m.def("eval_global_net_density", eval_global_net_density); - // m.def("eval_inst_num", eval_inst_num, py::arg("inst_status")); - // m.def("eval_net_num", eval_net_num, py::arg("net_type")); - // m.def("eval_pin_num", eval_pin_num, py::arg("inst_status")); - // m.def("eval_routing_layer_num", eval_routing_layer_num); - // m.def("eval_track_num", eval_track_num, py::arg("direction")); - // m.def("eval_track_remain_num", eval_track_remain_num); - // m.def("eval_track_overflow_num", eval_track_overflow_num); - // m.def("eval_chip_size", eval_chip_size, py::arg("region_type")); - // m.def("eval_inst_size", eval_inst_size, py::arg("inst_status"); - // m.def("eval_net_size", eval_net_size); - // m.def("eval_area", eval_area, py::arg("inst_status")); - // m.def("eval_macro_peri_area", eval_macro_peri_area); - // m.def("eval_area_util", eval_area_util, py::arg("inst_status")); - // m.def("eval_macro_channel_util", eval_macro_channel_util, py::arg("dist_ratio")); - // m.def("eval_macro_channel_pin_util", eval_macro_channel_pin_util, py::arg("dist_ratio")); + } } // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/py_feature/py_feature.cpp b/src/interface/python/py_feature/py_feature.cpp index 6e9d348cc4b78bf0f3d7d29757c7d9cc064c9a79..e337e8b05a95d623b7219f212506b64efe201c81 100644 --- a/src/interface/python/py_feature/py_feature.cpp +++ b/src/interface/python/py_feature/py_feature.cpp @@ -60,14 +60,14 @@ bool feature_eval_union(const std::string& jsonl_path, const std::string& csv_pa return featureInst->save_eval_union(jsonl_path, csv_path, grid_size); } -bool feature_pl_eval_union(const std::string& jsonl_path, const std::string& csv_path, int32_t grid_size) +bool feature_pl_eval(const std::string& json_path, int32_t grid_size) { - return featureInst->save_pl_eval_union(jsonl_path, csv_path, grid_size); + return featureInst->save_pl_eval(json_path, grid_size); } -bool feature_cts_eval_union(const std::string& jsonl_path, const std::string& csv_path, int32_t grid_size) +bool feature_cts_eval(const std::string& json_path, int32_t grid_size) { - return featureInst->save_cts_eval_union(jsonl_path, csv_path, grid_size); + return featureInst->save_cts_eval(json_path, grid_size); } bool feature_timing_eval_summary(const std::string& path) @@ -75,4 +75,9 @@ bool feature_timing_eval_summary(const std::string& path) return featureInst->save_timing_eval_summary(path); } +bool feature_cong_map(const std::string& step, const std::string& dir) +{ + return featureInst->save_cong_map(step, dir); +} + } // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/py_feature/py_feature.h b/src/interface/python/py_feature/py_feature.h index 22753cd40ad7d3caab21ce991325ba0aaf28fbb3..79a65512ab590fd0d3bf9d9182b5909c39ec4d26 100644 --- a/src/interface/python/py_feature/py_feature.h +++ b/src/interface/python/py_feature/py_feature.h @@ -22,14 +22,15 @@ namespace python_interface { bool feature_summary(const std::string& path); bool feature_tool(const std::string& path, const std::string& step); +bool feature_pl_eval(const std::string& json_path, int32_t grid_size = 1); +bool feature_cts_eval(const std::string& json_path, int32_t grid_size = 1); + bool feature_eval_map(const std::string& path, const int& bin_cnt_x, const int& bin_cnt_y); bool feature_route(const std::string& path); bool feature_route_read(const std::string& path); bool feature_eval_summary(const std::string& path, int32_t grid_size); bool feature_timing_eval_summary(const std::string& path); bool feature_net_eval(const std::string& path); -bool feature_eval_union(const std::string& jsonl_path, const std::string& csv_path, int32_t grid_size); -bool feature_pl_eval_union(const std::string& jsonl_path, const std::string& csv_path, int32_t grid_size); -bool feature_cts_eval_union(const std::string& jsonl_path, const std::string& csv_path, int32_t grid_size); +bool feature_cong_map(const std::string& step, const std::string& dir); } // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/py_feature/py_register_feature.h b/src/interface/python/py_feature/py_register_feature.h index 7d5471bb7c933bfa5ea27943a025dc0152dcd414..74a01ac7693b773a1b80db40dd8cf12ce5a03f2e 100644 --- a/src/interface/python/py_feature/py_register_feature.h +++ b/src/interface/python/py_feature/py_register_feature.h @@ -26,15 +26,16 @@ void register_feature(py::module& m) { m.def("feature_summary", feature_summary, py::arg("path")); m.def("feature_tool", feature_tool, py::arg("path"), py::arg("step")); + m.def("feature_pl_eval", feature_pl_eval, py::arg("json_path"), py::arg("grid_size")); + m.def("feature_cts_eval", feature_cts_eval, py::arg("json_path"), py::arg("grid_size")); + m.def("feature_eval_map", feature_eval_map, py::arg("path"), py::arg("bin_cnt_x"), py::arg("bin_cnt_y")); m.def("feature_route", feature_route, py::arg("path")); m.def("feature_route_read", feature_route_read, py::arg("path")); m.def("feature_eval_summary", feature_eval_summary, py::arg("path"), py::arg("grid_size")); m.def("feature_timing_eval_summary", feature_timing_eval_summary, py::arg("path")); m.def("feature_net_eval", feature_net_eval, py::arg("path")); - m.def("feature_eval_union", feature_eval_union, py::arg("jsonl_path"), py::arg("csv_path"), py::arg("grid_size")); - m.def("feature_pl_eval_union", feature_pl_eval_union, py::arg("jsonl_path"), py::arg("csv_path"), py::arg("grid_size")); - m.def("feature_cts_eval_union", feature_cts_eval_union, py::arg("jsonl_path"), py::arg("csv_path"), py::arg("grid_size")); + m.def("feature_cong_map", feature_cong_map, py::arg("step"), py::arg("dir")); } } // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/py_flow/py_flow.cpp b/src/interface/python/py_flow/py_flow.cpp index f91c8fa41787a5947fab2ca51bea5296b1731181..9159d99c111760101a31692941d1e3aafe433434 100644 --- a/src/interface/python/py_flow/py_flow.cpp +++ b/src/interface/python/py_flow/py_flow.cpp @@ -18,11 +18,7 @@ #include namespace python_interface { -bool flowAutoRun() -{ - iplf::plfInst->runFlow(); - return true; -} + bool flowExit() { std::exit(0); diff --git a/src/interface/python/py_flow/py_flow.h b/src/interface/python/py_flow/py_flow.h index 8256819d721e66d15de0723caed7ce95b3a40897..a00da9a5096dbd9e410e6e530213e4804fedb5f1 100644 --- a/src/interface/python/py_flow/py_flow.h +++ b/src/interface/python/py_flow/py_flow.h @@ -17,8 +17,6 @@ #pragma once namespace python_interface { - - bool flowAutoRun(); bool flowExit(); } \ No newline at end of file diff --git a/src/interface/python/py_flow/py_register_flow.h b/src/interface/python/py_flow/py_register_flow.h index 7452d1194944969e72756699d4ad406b243aa2c7..286d1bfa655475c45460dc72dc78b7abc59cb0ca 100644 --- a/src/interface/python/py_flow/py_register_flow.h +++ b/src/interface/python/py_flow/py_register_flow.h @@ -24,7 +24,6 @@ namespace python_interface { namespace py = pybind11; void register_flow(pybind11::module& m) { - m.def("flow_run", flowAutoRun); m.def("flow_exit", flowExit); } diff --git a/src/interface/python/py_ifp/py_ifp.cpp b/src/interface/python/py_ifp/py_ifp.cpp index e538d71af6ce4c4e6551ed6073852f7b72dbfee9..dbaca5570e5c24b245a6140693821e916333a845 100644 --- a/src/interface/python/py_ifp/py_ifp.cpp +++ b/src/interface/python/py_ifp/py_ifp.cpp @@ -25,10 +25,34 @@ namespace python_interface { bool fpInit(const std::string& die_area, const std::string& core_area, const std::string& core_site, const std::string& io_site, - const std::string& corner_site) + const std::string& corner_site, double core_util, double x_margin, double y_margin, double xy_ratio, double cell_area) { - auto die = ieda::Str::splitDouble(die_area.c_str(), " "); - auto core = ieda::Str::splitDouble(core_area.c_str(), " "); + std::vector die = ieda::Str::splitDouble(die_area.c_str(), " "); + std::vector core = ieda::Str::splitDouble(core_area.c_str(), " "); + if (die.empty() || core.empty()) { + // Get cell area - either from user input or get from iDB + if (cell_area <= 0) { + cell_area = dmInst->instanceArea(IdbInstanceType::kMax); + } + + // Calculate core area based on cell area and utilization + double total_core_area = cell_area / core_util; + + // Calculate core dimensions based on aspect ratio + double core_height = sqrt(total_core_area / xy_ratio); + double core_width = total_core_area / core_height; + + // Calculate die dimensions by adding margins + double die_width = core_width + 2 * x_margin; + double die_height = core_height + 2 * y_margin; + + // Set die area (llx, lly, urx, ury) + die = {0.0, 0.0, die_width, die_height}; + + // Set core area with margins + core = {x_margin, y_margin, x_margin + core_width, y_margin + core_height}; + } + fpApiInst->initDie(die[0], die[1], die[2], die[3]); fpApiInst->initCore(core[0], core[1], core[2], core[3], core_site, io_site, corner_site); return true; @@ -40,9 +64,9 @@ bool fpMakeTracks(const std::string& layer, int x_start, int x_step, int y_start return make_ok; } -bool fpPlacePins(const std::string& layer, int width, int height) +bool fpPlacePins(const std::string& layer, int width, int height, std::vector& sides) { - bool place_ok = fpApiInst->autoPlacePins(layer, width, height); + bool place_ok = fpApiInst->autoPlacePins(layer, width, height, sides); return place_ok; } diff --git a/src/interface/python/py_ifp/py_ifp.h b/src/interface/python/py_ifp/py_ifp.h index 71dcdadb74aa475079bcd865ce87f6c76071159e..cf88b5e80178a99110666788075225a898ee4eb0 100644 --- a/src/interface/python/py_ifp/py_ifp.h +++ b/src/interface/python/py_ifp/py_ifp.h @@ -22,9 +22,9 @@ namespace python_interface { bool fpInit(const std::string& die_area, const std::string& core_area, const std::string& core_site, const std::string& io_site, - const std::string& corner_site); + const std::string& corner_site, double core_util, double x_margin, double y_margin, double xy_ratio, double cell_area); bool fpMakeTracks(const std::string& layer, int x_start, int x_step, int y_start, int y_step); -bool fpPlacePins(const std::string& layer, int width, int height); +bool fpPlacePins(const std::string& layer, int width, int height, std::vector& sides); bool fpPlacePort(const std::string& pin_name, int offset_x, int offset_y, int width, int height, const std::string& layer); bool fpPlaceIOFiller(std::vector& filler_types, const std::string& prefix); bool fpAddPlacementBlockage(const std::string& box); diff --git a/src/interface/python/py_ifp/py_register_ifp.h b/src/interface/python/py_ifp/py_register_ifp.h index f5cc9af3c8909507b90f121f3631ef835bc037c2..9e2ae9952ff5649294cee075d3f08f13ff2b95eb 100644 --- a/src/interface/python/py_ifp/py_register_ifp.h +++ b/src/interface/python/py_ifp/py_register_ifp.h @@ -24,9 +24,9 @@ namespace py = pybind11; void register_ifp(py::module& m) { m.def("init_floorplan", fpInit, py::arg("die_area"), py::arg("core_area"), py::arg("core_site"), py::arg("io_site"), - py::arg("corner_site")); + py::arg("corner_site"), py::arg("core_util"), py::arg("x_margin"), py::arg("y_margin"), py::arg("xy_ratio"), py::arg("cell_area")); m.def("gern_track", fpMakeTracks, py::arg("layer"), py::arg("x_start"), py::arg("x_step"), py::arg("y_start"), py::arg("y_step")); - m.def("auto_place_pins", fpPlacePins, py::arg("layer"), py::arg("width"), py::arg("height")); + m.def("auto_place_pins", fpPlacePins, py::arg("layer"), py::arg("width"), py::arg("height"), py::arg("sides")); m.def("place_port", fpPlacePort, py::arg("pin_name"), py::arg("offset_x"), py::arg("offset_y"), py::arg("width"), py::arg("height"), py::arg("layer")); m.def("place_io_filler", fpPlaceIOFiller, py::arg("filler_types"), py::arg("prefix") = "IOFill"); diff --git a/src/interface/python/py_ipdn/py_ipdn.cpp b/src/interface/python/py_ipdn/py_ipdn.cpp index 4d00f0a7071c8885a2025524921e15a03f9293c9..574550df2abf3895751cb14e18c76f1b8d8a55cb 100644 --- a/src/interface/python/py_ipdn/py_ipdn.cpp +++ b/src/interface/python/py_ipdn/py_ipdn.cpp @@ -22,7 +22,7 @@ namespace python_interface { bool pdnAddIO(const std::string& pin_name, const std::string& net_name, const std::string& direction, bool is_power) { - const std::string& pin = pin_name.empty() ? net_name : pin; + const std::string pin = pin_name.empty() ? net_name : pin_name; pdnApiInst->addIOPin(pin, net_name, direction, is_power); return true; } diff --git a/src/interface/python/py_ipnp/CMakeLists.txt b/src/interface/python/py_ipnp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7fec1af0dc0961e3f163eb22a4418b570c30c436 --- /dev/null +++ b/src/interface/python/py_ipnp/CMakeLists.txt @@ -0,0 +1,14 @@ +aux_source_directory(. PY_IPNP_SRC) + +add_library(py_ipnp ${PY_IPNP_SRC}) + +target_link_libraries(py_ipnp + PUBLIC + tool_manager + ipnp_api + pybind11::pybind11 +) +target_include_directories(py_ipnp + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/src/interface/python/py_ipnp/py_ipnp.cpp b/src/interface/python/py_ipnp/py_ipnp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9bae4a3eeb3805f521003edb46f650f127407d7 --- /dev/null +++ b/src/interface/python/py_ipnp/py_ipnp.cpp @@ -0,0 +1,28 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#include "py_ipnp.h" + +#include "tool_manager.h" + +namespace python_interface { + +bool run_pnp(const std::string& config) +{ + return iplf::tmInst->autoRunPNP(config); +} + +} // namespace python_interface \ No newline at end of file diff --git a/src/operation/iPNP/source/include/iPNPCommon.hh b/src/interface/python/py_ipnp/py_ipnp.h similarity index 68% rename from src/operation/iPNP/source/include/iPNPCommon.hh rename to src/interface/python/py_ipnp/py_ipnp.h index e8e59dae982ed3f5c42806a9ec57d282534b3d74..246740d2d03a1d4664332d7bb35a425f1e016c6c 100644 --- a/src/operation/iPNP/source/include/iPNPCommon.hh +++ b/src/interface/python/py_ipnp/py_ipnp.h @@ -14,26 +14,11 @@ // // See the Mulan PSL v2 for more details. // *************************************************************************************** -/** - * @file iPNPCommon.hh - * @author Xinhao li - * @brief - * @version 0.1 - * @date 2024-07-15 - */ - #pragma once -#include "IdbCellMaster.h" -#include "IdbDesign.h" -#include "IdbEnum.h" -#include "IdbGeometry.h" -#include "IdbInstance.h" -#include "IdbLayer.h" -#include "IdbLayout.h" -#include "IdbNet.h" -#include "IdbPins.h" -#include "builder.h" -#include "def_service.h" -#include "lef_service.h" -#include "log/Log.hh" +#include +#include + +namespace python_interface { +bool run_pnp(const std::string& config); +} // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/py_ipnp/py_register_ipnp.h b/src/interface/python/py_ipnp/py_register_ipnp.h new file mode 100644 index 0000000000000000000000000000000000000000..d66feb11dc99ea1e9ca95cc8e0b0db5615df07f2 --- /dev/null +++ b/src/interface/python/py_ipnp/py_register_ipnp.h @@ -0,0 +1,29 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include +#include + +#include "py_ipnp.h" +namespace python_interface { +namespace py = pybind11; + +void register_ipnp(py::module& m) +{ + m.def("run_pnp", run_pnp, py::arg("config")); +} +} // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/py_ista/py_ista.cpp b/src/interface/python/py_ista/py_ista.cpp index 9d82fb0d2ff4f0a5d9a175b1452ac5bcfda7a633..36e2e2222e20a347b4aa5c29e3857fe115ba84d7 100644 --- a/src/interface/python/py_ista/py_ista.cpp +++ b/src/interface/python/py_ista/py_ista.cpp @@ -171,6 +171,7 @@ bool updateRCTreeInfo(const std::string& net_name) { bool updateTiming() { auto* ista = ista::Sta::getOrCreateSta(); + ista->buildGraph(); ista->updateTiming(); return true; } @@ -182,7 +183,36 @@ bool reportSta() return true; } +std::vector getWireTimingData(unsigned n_worst_path_per_clock) +{ + auto* ista = ista::Sta::getOrCreateSta(); + auto path_wire_timing_data = ista->reportTimingData(n_worst_path_per_clock); + + std::vector ret_timing_data; + + for (auto& one_path_wire_timing_data : path_wire_timing_data) { + PathWireTimingData ret_one_path_data; + for (auto& wire_timing_data : one_path_wire_timing_data) { + WireTimingData ret_wire_data; + ret_wire_data._from_node_name = std::move(wire_timing_data._from_node_name); + ret_wire_data._to_node_name = std::move(wire_timing_data._to_node_name); + ret_wire_data._wire_resistance = wire_timing_data._wire_resistance; + ret_wire_data._wire_capacitance = wire_timing_data._wire_capacitance; + ret_wire_data._wire_delay = wire_timing_data._wire_delay; + ret_wire_data._wire_from_slew = wire_timing_data._wire_from_slew; + ret_wire_data._wire_to_slew = wire_timing_data._wire_to_slew; + + ret_one_path_data.emplace_back(std::move(ret_wire_data)); + } + ret_timing_data.emplace_back(std::move(ret_one_path_data)); + + } + + LOG_INFO << "get wire data size: " << ret_timing_data.size(); + + return ret_timing_data; +} bool reportTiming(int digits, const std::string& delay_type, std::set exclude_cell_names, bool derate) { diff --git a/src/interface/python/py_ista/py_ista.h b/src/interface/python/py_ista/py_ista.h index 116e3ee880733ac00dd073347f89efcee70e01be..4b7ef51f691d5cd512312ab7cdb4dbc96880d904 100644 --- a/src/interface/python/py_ista/py_ista.h +++ b/src/interface/python/py_ista/py_ista.h @@ -20,7 +20,22 @@ #include #include + namespace python_interface { + +struct WireTimingData +{ + std::string _from_node_name; + std::string _to_node_name; + double _wire_resistance; + double _wire_capacitance; + double _wire_from_slew; + double _wire_to_slew; + double _wire_delay; +}; + +using PathWireTimingData = std::vector; + bool staRun(const std::string& output); bool staInit(const std::string& output); @@ -53,6 +68,8 @@ bool updateRCTreeInfo(const std::string& net_name); bool updateTiming(); bool reportSta(); +std::vector getWireTimingData(unsigned n_worst_path_per_clock); + bool reportTiming(int digits, const std::string& delay_type, std::set exclude_cell_names, bool derate); std::vector get_used_libs(); diff --git a/src/interface/python/py_ista/py_register_ista.h b/src/interface/python/py_ista/py_register_ista.h index 3888f46bce8d5798797383390529e66c82a5672c..5aa12136bce99020d9fafc690ea9215cf96200f7 100644 --- a/src/interface/python/py_ista/py_register_ista.h +++ b/src/interface/python/py_ista/py_register_ista.h @@ -51,5 +51,17 @@ void register_ista(py::module& m) m.def("report_timing", reportTiming, py::arg("digits"), py::arg("delay_type"), py::arg("exclude_cell_names"), py::arg("derate")); m.def("get_used_libs", get_used_libs); + + // get wire timing data + py::class_(m, "WireTimingData") + .def_readwrite("from_node_name", &WireTimingData::_from_node_name) + .def_readwrite("to_node_name", &WireTimingData::_to_node_name) + .def_readwrite("wire_resistance", &WireTimingData::_wire_resistance) + .def_readwrite("wire_capacitance", &WireTimingData::_wire_capacitance) + .def_readwrite("wire_from_slew", &WireTimingData::_wire_from_slew) + .def_readwrite("wire_to_slew", &WireTimingData::_wire_to_slew) + .def_readwrite("wire_delay", &WireTimingData::_wire_delay); + + m.def("get_wire_timing_data", getWireTimingData); } } // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/py_vec/CMakeLists.txt b/src/interface/python/py_vec/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d08df9a9d6d36e83d09c73a7c7dfe2046cb97d1 --- /dev/null +++ b/src/interface/python/py_vec/CMakeLists.txt @@ -0,0 +1,14 @@ +aux_source_directory(. PY_VEC_SRC) + +add_library(py_vec ${PY_VEC_SRC}) + +target_link_libraries(py_vec + PUBLIC + ivec_api + pybind11::pybind11 + +) +target_include_directories(py_vec + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/src/interface/python/py_vec/py_register_vec.h b/src/interface/python/py_vec/py_register_vec.h new file mode 100644 index 0000000000000000000000000000000000000000..4515b6eefe7c18661469b32a11ced1dc0197567f --- /dev/null +++ b/src/interface/python/py_vec/py_register_vec.h @@ -0,0 +1,49 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include +#include + +#include "py_vec.h" + +namespace python_interface { +namespace py = pybind11; +void register_vectorization(py::module& m) +{ + m.def("layout_patchs", layout_patchs, py::arg("path")); + m.def("layout_graph", layout_graph, py::arg("path")); + m.def("generate_vectors", generate_vectors, py::arg("dir"), py::arg("patch_row_step") = 9, py::arg("patch_col_step") = 9); + + py::class_(m, "TimingWireNode") + .def_readwrite("name", &ieval::TimingWireNode::_name) + .def_readwrite("is_pin", &ieval::TimingWireNode::_is_pin) + .def_readwrite("is_port", &ieval::TimingWireNode::_is_port); + + py::class_(m, "TimingWireEdge") + .def_readwrite("from_node", &ieval::TimingWireEdge::_from_node) + .def_readwrite("to_node", &ieval::TimingWireEdge::_to_node) + .def_readwrite("is_net_edge", &ieval::TimingWireEdge::_is_net_edge); + + py::class_(m, "TimingWireGraph") + .def_readwrite("nodes", &ieval::TimingWireGraph::_nodes) + .def_readwrite("edges", &ieval::TimingWireGraph::_edges); + + m.def("get_timing_wire_graph", &get_timing_wire_graph); + m.def("get_timing_instance_graph", &get_timing_instance_graph); +} + +} // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/py_vec/py_vec.cpp b/src/interface/python/py_vec/py_vec.cpp new file mode 100644 index 0000000000000000000000000000000000000000..818c6ff05fc1414f7d4eb606ed18725de6979fcf --- /dev/null +++ b/src/interface/python/py_vec/py_vec.cpp @@ -0,0 +1,85 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#include "py_vec.h" + +#include + +#include "timing_api.hh" +#include "vec_api.h" + +namespace python_interface { + +bool layout_patchs(const std::string& path) +{ + ivec::VectorizationApi lm_api; + return lm_api.buildVectorizationLayoutData(path); +} + +bool layout_graph(const std::string& path) +{ + ivec::VectorizationApi lm_api; + return lm_api.buildVectorizationGraphData(path); +} + +bool generate_vectors(std::string dir, int patch_row_step, int patch_col_step) +{ + if (dir == "") { + dir = "./vectors"; + } + ivec::VectorizationApi lm_api; + return lm_api.buildVectorizationFeature(dir, patch_row_step, patch_col_step); +} + +ieval::TimingWireGraph get_timing_wire_graph(std::string wire_graph_path) +{ + if (std::filesystem::exists(wire_graph_path)) { + auto timing_wire_graph = ieval::RestoreTimingGraph(wire_graph_path); + return timing_wire_graph; + } + + ivec::VectorizationApi lm_api; + lm_api.runVecSTA(); + + auto* timing_wire_graph_ptr = ieval::TimingAPI::getInst()->getTimingWireGraph(); + ieval::SaveTimingGraph(*timing_wire_graph_ptr, wire_graph_path); + + auto timing_wire_graph = std::move(*timing_wire_graph_ptr); + delete timing_wire_graph_ptr; + + return timing_wire_graph; +} + +ieval::TimingInstanceGraph get_timing_instance_graph(std::string instance_graph_path) +{ + if (std::filesystem::exists(instance_graph_path)) { + auto timing_instance_graph = ieval::RestoreTimingInstanceGraph(instance_graph_path); + return timing_instance_graph; + } + + ivec::VectorizationApi lm_api; + lm_api.runVecSTA(); + + auto* timing_instance_graph_ptr = ieval::TimingAPI::getInst()->getTimingInstanceGraph(); + ieval::SaveTimingInstanceGraph(*timing_instance_graph_ptr, instance_graph_path); + + auto timing_instance_graph = std::move(*timing_instance_graph_ptr); + delete timing_instance_graph_ptr; + + return timing_instance_graph; +} + +} // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/py_vec/py_vec.h b/src/interface/python/py_vec/py_vec.h new file mode 100644 index 0000000000000000000000000000000000000000..15c3b24bf69e74d0b305aa29afa981272864811a --- /dev/null +++ b/src/interface/python/py_vec/py_vec.h @@ -0,0 +1,33 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once + +#include + +#include "init_sta.hh" + +namespace python_interface { + +bool layout_patchs(const std::string& path); +bool layout_graph(const std::string& path); +bool generate_vectors(std::string dir, int patch_row_step, int patch_col_step); + +// for vectorization wire timing graph. +ieval::TimingWireGraph get_timing_wire_graph(std::string wire_graph_path); +ieval::TimingInstanceGraph get_timing_instance_graph(std::string instance_graph_path); + +} // namespace python_interface \ No newline at end of file diff --git a/src/interface/python/python_moodule.cpp b/src/interface/python/python_moodule.cpp index 123589ccd100779b7185ce4e375eb0cc3f2ae19a..c50aecd0665bcb39bf9b586c6b57d4f736dced78 100644 --- a/src/interface/python/python_moodule.cpp +++ b/src/interface/python/python_moodule.cpp @@ -26,12 +26,14 @@ #include "py_register_ino.h" #include "py_register_inst.h" #include "py_register_ipdn.h" +#include "py_register_ipnp.h" #include "py_register_ipl.h" #include "py_register_ipw.h" #include "py_register_irt.h" #include "py_register_ista.h" #include "py_register_ito.h" #include "py_register_report.h" +#include "py_register_vec.h" #include "python_module.h" namespace python_interface { @@ -48,6 +50,7 @@ PYBIND11_MODULE(ieda_py, m) register_ino(m); register_inst(m); register_ipdn(m); + register_ipnp(m); register_ipl(m); register_irt(m); register_ista(m); @@ -56,6 +59,7 @@ PYBIND11_MODULE(ieda_py, m) register_report(m); register_feature(m); register_eval(m); + register_vectorization(m); } } // namespace python_interface \ No newline at end of file diff --git a/src/interface/tcl/CMakeLists.txt b/src/interface/tcl/CMakeLists.txt index 6ae922bdd2dbb2963f72db27c1bc6ca832e9c2a2..78925efba9e8e92c717239f2297855d86bf8b15a 100644 --- a/src/interface/tcl/CMakeLists.txt +++ b/src/interface/tcl/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(tcl_instance) add_subdirectory(tcl_irt) add_subdirectory(tcl_ifp) add_subdirectory(tcl_ipdn) +add_subdirectory(tcl_ipnp) if(BUILD_GUI) add_subdirectory(tcl_gui) endif() @@ -20,6 +21,8 @@ add_subdirectory(tcl_ino) add_subdirectory(tcl_feature) add_subdirectory(tcl_eval) add_subdirectory(tcl_eco) +add_subdirectory(tcl_vec) +add_subdirectory(tcl_notification) if(CONTEST) add_subdirectory(tcl_contest) @@ -53,11 +56,15 @@ target_link_libraries(ieda_tcl tcl_feature tcl_eval tcl_eco + tcl_vec + tcl_ipnp + tcl_notification ) target_include_directories(ieda_tcl PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/tcl_ipnp ${HOME_UTILITY}/tcl diff --git a/src/interface/tcl/tcl_definition.h b/src/interface/tcl/tcl_definition.h index 7994bc49ae14ec1e01f17ff37ca2f04236b73232..209778557d4d5482685510baae3a82460629f047 100644 --- a/src/interface/tcl/tcl_definition.h +++ b/src/interface/tcl/tcl_definition.h @@ -35,6 +35,8 @@ namespace tcl { #define TCL_WORK_DIR "-work_dir" #define TCL_STEP "-step" #define TCL_ADD_SPACE "-add_space" +#define TCL_PATCH_ROW_STEP "-patch_row_step" +#define TCL_PATCH_COL_STEP "-patch_col_step" const char* const EMPTY_STR = ""; diff --git a/src/interface/tcl/tcl_eval/tcl_register_eval.h b/src/interface/tcl/tcl_eval/tcl_register_eval.h index 2aa05a1a096faac7ef199bc0c85204ff3010be22..0ca904a65942357ed967a994294fade9afddbbb8 100644 --- a/src/interface/tcl/tcl_eval/tcl_register_eval.h +++ b/src/interface/tcl/tcl_eval/tcl_register_eval.h @@ -33,7 +33,6 @@ namespace tcl { int registerCmdEval() { - registerTclCmd(CmdEvalInit, "init_cong_eval"); registerTclCmd(CmdEvalTimingRun, "run_timing_eval"); registerTclCmd(CmdEvalWirelengthRun, "run_wirelength_eval"); registerTclCmd(CmdEvalDensityRun, "run_density_eval"); diff --git a/src/interface/tcl/tcl_flow/tcl_flow.cpp b/src/interface/tcl/tcl_flow/tcl_flow.cpp index 5717cbb7a6f542689dce9dcabc8127c4e8ed542c..267b2fb82776b72f4e62b4769d9cd14de6b4f701 100644 --- a/src/interface/tcl/tcl_flow/tcl_flow.cpp +++ b/src/interface/tcl/tcl_flow/tcl_flow.cpp @@ -30,35 +30,6 @@ namespace tcl { -CmdFlowAutoRun::CmdFlowAutoRun(const char* cmd_name) : TclCmd(cmd_name) -{ - // auto* file_name_option = new TclStringOption(TCL_CONFIG, 1, nullptr); - // addOption(file_name_option); -} - -unsigned CmdFlowAutoRun::check() -{ - // TclOption* file_name_option = getOptionOrArg(TCL_CONFIG); - // LOG_FATAL_IF(!file_name_option); - return 1; -} - -unsigned CmdFlowAutoRun::exec() -{ - if (!check()) { - return 0; - } - - // TclOption* option = getOptionOrArg(TCL_CONFIG); - // auto data_config = option->getStringVal(); - iplf::plfInst->runFlow(); - - return 1; -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - CmdFlowExit::CmdFlowExit(const char* cmd_name) : TclCmd(cmd_name) { } diff --git a/src/interface/tcl/tcl_flow/tcl_flow.h b/src/interface/tcl/tcl_flow/tcl_flow.h index 7deff3d271079ed48ce93ebd3c2330a2947f62c1..210c854093b52f5aac523f34a7e784af87b78a53 100644 --- a/src/interface/tcl/tcl_flow/tcl_flow.h +++ b/src/interface/tcl/tcl_flow/tcl_flow.h @@ -35,20 +35,6 @@ using ieda::TclStringOption; namespace tcl { -class CmdFlowAutoRun : public TclCmd -{ - public: - explicit CmdFlowAutoRun(const char* cmd_name); - ~CmdFlowAutoRun() override = default; - - unsigned check() override; - unsigned exec() override; - - private: - // private function - // private data -}; - class CmdFlowExit : public TclCmd { public: diff --git a/src/interface/tcl/tcl_flow/tcl_register_flow.h b/src/interface/tcl/tcl_flow/tcl_register_flow.h index fcb8372f9043c26aa4ace000d6db74f234139d94..6723d59b1d853b0b840ad54b36d7931fdc13870f 100644 --- a/src/interface/tcl/tcl_flow/tcl_register_flow.h +++ b/src/interface/tcl/tcl_flow/tcl_register_flow.h @@ -34,7 +34,6 @@ namespace tcl { int registerCmdFlow() { - registerTclCmd(CmdFlowAutoRun, "flow_run"); registerTclCmd(CmdFlowExit, "flow_exit"); registerTclCmd(CmdFlowConfig, "flow_config"); return EXIT_SUCCESS; diff --git a/src/interface/tcl/tcl_gui/CMakeLists.txt b/src/interface/tcl/tcl_gui/CMakeLists.txt index 68aa8db80a6b83fe8a841d03384d3f6a526bad03..08d1a0e9df1f21272737ec334467328a28753e5b 100644 --- a/src/interface/tcl/tcl_gui/CMakeLists.txt +++ b/src/interface/tcl/tcl_gui/CMakeLists.txt @@ -12,6 +12,7 @@ target_link_libraries(tcl_gui str iGUI tcl_qt + ivec_api ) target_include_directories(tcl_gui diff --git a/src/interface/tcl/tcl_gui/tcl_gui.cpp b/src/interface/tcl/tcl_gui/tcl_gui.cpp index 874a129a85a3bc5dd717a6383fa5e819b616b114..ff37671e6a06835f8dbbb52389c53d41f8c5ecad 100644 --- a/src/interface/tcl/tcl_gui/tcl_gui.cpp +++ b/src/interface/tcl/tcl_gui/tcl_gui.cpp @@ -25,6 +25,7 @@ #include "tcl_gui.h" #include "gui_io.h" +#include "lm_api.h" #include "tool_manager.h" namespace tcl { @@ -221,4 +222,41 @@ unsigned CmdGuiShowPlacement::exec() return 1; } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CmdGuiShowGraph::CmdGuiShowGraph(const char* cmd_name) : TclCmd(cmd_name) +{ + auto* path_opt = new TclStringOption(TCL_PATH, 1, nullptr); + addOption(path_opt); +} + +unsigned CmdGuiShowGraph::check() +{ + // TclOption *file_name_option = getOptionOrArg("-path"); + // LOG_FATAL_IF(!file_name_option); + return 1; +} + +unsigned CmdGuiShowGraph::exec() +{ + if (!check()) { + return 0; + } + std::cout << "333" << std::endl; + std::string path = ""; + TclOption* path_opt = getOptionOrArg(TCL_PATH); + if (path_opt != nullptr) { + path = path_opt->getStringVal(); + } + std::cout << "2222" << std::endl; + ivec::VectorizationApi lm_api; + auto data = lm_api.getGraph(path); + + std::cout << "11111" << std::endl; + iplf::tmInst->guiShowGraph(data); + + return 1; +} + } // namespace tcl diff --git a/src/interface/tcl/tcl_gui/tcl_gui.h b/src/interface/tcl/tcl_gui/tcl_gui.h index 474404e4e012e5f84660c4af6f1ddf5a15df4963..48763c87dafdf979785843c5e39e17b75ab08db0 100644 --- a/src/interface/tcl/tcl_gui/tcl_gui.h +++ b/src/interface/tcl/tcl_gui/tcl_gui.h @@ -120,4 +120,18 @@ class CmdGuiShowPlacement : public TclCmd // private data }; +class CmdGuiShowGraph : public TclCmd +{ + public: + explicit CmdGuiShowGraph(const char* cmd_name); + ~CmdGuiShowGraph() override = default; + + unsigned check() override; + unsigned exec() override; + + private: + // private function + // private data +}; + } // namespace tcl \ No newline at end of file diff --git a/src/interface/tcl/tcl_gui/tcl_register_gui.h b/src/interface/tcl/tcl_gui/tcl_register_gui.h index 807fd28fb5a52452923990cf9a4be6e494b6874a..87131ff7d11c9708228a914d315214406ed1d6fd 100644 --- a/src/interface/tcl/tcl_gui/tcl_register_gui.h +++ b/src/interface/tcl/tcl_gui/tcl_register_gui.h @@ -42,6 +42,7 @@ int registerCmdGUI() registerTclCmd(CmdGuiShowDrc, "gui_show_drc"); registerTclCmd(CmdGuiShowClockTree, "gui_show_cts"); registerTclCmd(CmdGuiShowPlacement, "gui_show_pl"); + registerTclCmd(CmdGuiShowGraph, "gui_show_graph"); // web registerTclCmd(CmdCaptureDesign, "capture_design"); diff --git a/src/interface/tcl/tcl_ifp/tcl_init_ifp.cpp b/src/interface/tcl/tcl_ifp/tcl_init_ifp.cpp index 8460b185c8b227b102365d9f944ee7205f063b5b..5fb7be022658e422fff067488538b7879123e8c7 100644 --- a/src/interface/tcl/tcl_ifp/tcl_init_ifp.cpp +++ b/src/interface/tcl/tcl_ifp/tcl_init_ifp.cpp @@ -19,16 +19,27 @@ #include "ifp_api.h" #include "tcl_ifp.h" #include "tool_manager.h" +#include namespace tcl { TclFpInit::TclFpInit(const char* cmd_name) : TclCmd(cmd_name) { - auto* tcl_file_name = new TclStringOption("-die_area", 0, nullptr); + auto* core_util = new TclDoubleOption("-core_util", 0); + auto* cell_area = new TclDoubleOption("-cell_area", 0); + auto* x_margin = new TclDoubleOption("-x_margin", 0, 10.0); + auto* y_margin = new TclDoubleOption("-y_margin", 0, 10.0); + auto* xy_ratio = new TclDoubleOption("-xy_ratio", 0, 1.0); + auto* tcl_die_area = new TclStringOption("-die_area", 0, nullptr); auto* tcl_core_area = new TclStringOption("-core_area", 0, nullptr); auto* tcl_core_site = new TclStringOption("-core_site", 0, nullptr); auto* tcl_io_site = new TclStringOption("-io_site", 0, nullptr); auto* tcl_corner_site = new TclStringOption("-corner_site", 0, nullptr); - addOption(tcl_file_name); + addOption(core_util); + addOption(cell_area); + addOption(x_margin); + addOption(y_margin); + addOption(xy_ratio); + addOption(tcl_die_area); addOption(tcl_core_area); addOption(tcl_core_site); addOption(tcl_io_site); @@ -37,13 +48,22 @@ TclFpInit::TclFpInit(const char* cmd_name) : TclCmd(cmd_name) unsigned TclFpInit::check() { - TclOption* tcl_file_name = getOptionOrArg("-die_area"); + TclOption* tcl_die_area = getOptionOrArg("-die_area"); TclOption* tcl_core_area = getOptionOrArg("-core_area"); TclOption* tcl_core_site = getOptionOrArg("-core_site"); + TclOption* core_util = getOptionOrArg("-core_util"); // TclOption* tcl_io_site = getOptionOrArg("-io_site"); // TclOption* tcl_corner_site = getOptionOrArg("-corner_site"); - LOG_FATAL_IF(!tcl_file_name); - LOG_FATAL_IF(!tcl_core_area); + + // Check if either explicit areas are provided OR automatic calculation parameters are provided + bool has_explicit_areas = tcl_die_area && tcl_die_area->is_set_val() && + tcl_core_area && tcl_core_area->is_set_val(); + bool has_auto_calc_params = core_util && core_util->is_set_val(); + // Note: cell_area is now optional - if not provided, it will be retrieved from netlist + + LOG_FATAL_IF(!has_explicit_areas && !has_auto_calc_params) + << "Either provide explicit -die_area and -core_area, or provide -core_util for automatic calculation (cell_area is optional)"; + LOG_FATAL_IF(!tcl_core_site); // LOG_FATAL_IF(!tcl_io_site); // LOG_FATAL_IF(!tcl_corner_site); @@ -56,18 +76,64 @@ unsigned TclFpInit::exec() return 0; } - TclOption* tcl_file_name = getOptionOrArg("-die_area"); + TclOption* tcl_die_area = getOptionOrArg("-die_area"); TclOption* tcl_core_area = getOptionOrArg("-core_area"); TclOption* tcl_core_site = getOptionOrArg("-core_site"); TclOption* tcl_io_site = getOptionOrArg("-io_site"); TclOption* tcl_corner_site = getOptionOrArg("-corner_site"); + TclOption* core_util = getOptionOrArg("-core_util"); + TclOption* cell_area = getOptionOrArg("-cell_area"); + TclOption* x_margin = getOptionOrArg("-x_margin"); + TclOption* y_margin = getOptionOrArg("-y_margin"); + TclOption* xy_ratio = getOptionOrArg("-xy_ratio"); ieda::Str str = ieda::Str(); - // auto idb_design = dmInst->get_idb_design(); + std::vector die_area; + std::vector core_area; + + // Check if explicit areas are provided + bool has_explicit_areas = tcl_die_area && tcl_die_area->is_set_val() && + tcl_core_area && tcl_core_area->is_set_val(); + + if (has_explicit_areas) { + // Use explicitly provided areas + die_area = str.splitDouble(tcl_die_area->getStringVal(), " "); + core_area = str.splitDouble(tcl_core_area->getStringVal(), " "); + } else { + // Calculate die and core bounding box using core_util + double util = core_util->getDoubleVal(); + + // Get cell area - either from user input or get from iDB + double cell_area_val; + if (cell_area && cell_area->is_set_val()) { + cell_area_val = cell_area->getDoubleVal(); + } else { + cell_area_val = dmInst->instanceArea(IdbInstanceType::kMax); + } + + double x_margin_val = x_margin->getDoubleVal(); + double y_margin_val = y_margin->getDoubleVal(); + double ratio = xy_ratio->getDoubleVal(); + + // Calculate core area based on cell area and utilization + double total_core_area = cell_area_val / util; + + // Calculate core dimensions based on aspect ratio + double core_height = sqrt(total_core_area / ratio); + double core_width = total_core_area / core_height; + + // Calculate die dimensions by adding margins + double die_width = core_width + 2 * x_margin_val; + double die_height = core_height + 2 * y_margin_val; + + // Set die area (llx, lly, urx, ury) + die_area = {0.0, 0.0, die_width, die_height}; + + // Set core area with margins + core_area = {x_margin_val, y_margin_val, x_margin_val + core_width, y_margin_val + core_height}; + } - std::vector die_area = str.splitDouble(tcl_file_name->getStringVal(), " "); - std::vector core_area = str.splitDouble(tcl_core_area->getStringVal(), " "); string core_site = tcl_core_site->getStringVal(); string io_site = tcl_io_site->getStringVal() == nullptr ? core_site : tcl_io_site->getStringVal(); string corner_site = tcl_corner_site->getStringVal() == nullptr ? io_site : tcl_corner_site->getStringVal(); diff --git a/src/interface/tcl/tcl_ifp/tcl_io.cpp b/src/interface/tcl/tcl_ifp/tcl_io.cpp index 243883bcb513defc28fc080f34a499af368b78c8..b03e39aa1575fbfbe362f4732d8eec1e88fdf413 100644 --- a/src/interface/tcl/tcl_ifp/tcl_io.cpp +++ b/src/interface/tcl/tcl_ifp/tcl_io.cpp @@ -27,10 +27,12 @@ TclFpPlacePins::TclFpPlacePins(const char* cmd_name) : TclCmd(cmd_name) auto* tcl_layer = new TclStringOption("-layer", 0); auto* tcl_width = new TclIntOption("-width", 0); auto* tcl_height = new TclIntOption("-height", 0); + auto* tcl_sides = new TclStringListOption("-sides", 1); /// -sides "left right top bottom" addOption(tcl_layer); addOption(tcl_width); addOption(tcl_height); + addOption(tcl_sides); } unsigned TclFpPlacePins::check() @@ -47,12 +49,18 @@ unsigned TclFpPlacePins::exec() TclOption* tcl_layer = getOptionOrArg("-layer"); TclOption* tcl_width = getOptionOrArg("-width"); TclOption* tcl_height = getOptionOrArg("-height"); + TclOption* tcl_sides = getOptionOrArg("-sides"); auto layer = tcl_layer->getStringVal(); auto width = tcl_width->getIntVal(); auto height = tcl_height->getIntVal(); + vector sides = {}; - fpApiInst->autoPlacePins(layer, width, height); + if (tcl_sides != nullptr) { + sides = tcl_sides->getStringList(); + } + + fpApiInst->autoPlacePins(layer, width, height, sides); std::cout << "Floorplan place pins." << std::endl; return 1; diff --git a/src/interface/tcl/tcl_ipdn/CMakeLists.txt b/src/interface/tcl/tcl_ipdn/CMakeLists.txt index 59dc9a963e3af78acc3f1e73c6fec5db492ad74b..456712fc60e1ff69766f91475d3c6dff6c9081f3 100644 --- a/src/interface/tcl/tcl_ipdn/CMakeLists.txt +++ b/src/interface/tcl/tcl_ipdn/CMakeLists.txt @@ -11,7 +11,6 @@ target_link_libraries(tcl_ipdn str tool_manager ipdn_api - iPNPApi ) target_include_directories(tcl_ipdn diff --git a/src/interface/tcl/tcl_ipdn/tcl_ipdn.cpp b/src/interface/tcl/tcl_ipdn/tcl_ipdn.cpp index 0e26f7828e8d247ee79cc085ad5d520527775ef7..e330cb81bb92093006baa6ec1ca5233df2bb0221 100644 --- a/src/interface/tcl/tcl_ipdn/tcl_ipdn.cpp +++ b/src/interface/tcl/tcl_ipdn/tcl_ipdn.cpp @@ -17,9 +17,9 @@ #include "tcl_ipdn.h" #include "Str.hh" -// #include "iPNPApi.hh" #include "idm.h" #include "ipdn_api.h" +#include "ipnp_api.hh" #include "tool_manager.h" namespace tcl { diff --git a/src/interface/tcl/tcl_ipdn/tcl_register_pdn.h b/src/interface/tcl/tcl_ipdn/tcl_register_pdn.h index 94c0b0600806d502101ddabe43d78db691fe15ae..6395eea528dcb932571bc8bc4106bded133da4a3 100644 --- a/src/interface/tcl/tcl_ipdn/tcl_register_pdn.h +++ b/src/interface/tcl/tcl_ipdn/tcl_register_pdn.h @@ -44,8 +44,7 @@ int registerCmdPDN() registerTclCmd(TclPdnConnectStripe, "connect_pdn_stripe"); registerTclCmd(TclPdnAddSegmentStripe, "add_segment_stripe"); registerTclCmd(TclPdnAddSegmentVia, "add_segment_via"); - registerTclCmd(TclRunPNP, "run_pnp"); - ///如要增加,直接拷贝即可 + // registerTclCmd(TclRunPNP, "run_pnp"); return EXIT_SUCCESS; } diff --git a/src/interface/tcl/tcl_ipnp/CMakeLists.txt b/src/interface/tcl/tcl_ipnp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4062f277d392ba9dd131dd9894cfbae23b063606 --- /dev/null +++ b/src/interface/tcl/tcl_ipnp/CMakeLists.txt @@ -0,0 +1,20 @@ +AUX_SOURCE_DIRECTORY(./ TCL_IPNP_SRC) + +add_library(tcl_ipnp + ${TCL_IPNP_SRC} +) + +target_link_libraries(tcl_ipnp + PUBLIC + tool_manager + tcl + shell-cmd + str + tcl_util + ipnp_api +) + +target_include_directories(tcl_ipnp + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/src/operation/iPNP/source/module/tcl-cmd/CmdAddVIA1.cc b/src/interface/tcl/tcl_ipnp/tcl_ipnp.cpp similarity index 31% rename from src/operation/iPNP/source/module/tcl-cmd/CmdAddVIA1.cc rename to src/interface/tcl/tcl_ipnp/tcl_ipnp.cpp index 72ea5cbbfe7b0e5a68f360cc07917a6ac9cc51b0..3619c10aa27716cc6c08c35e45ee16deaf01790b 100644 --- a/src/operation/iPNP/source/module/tcl-cmd/CmdAddVIA1.cc +++ b/src/interface/tcl/tcl_ipnp/tcl_ipnp.cpp @@ -14,81 +14,85 @@ // // See the Mulan PSL v2 for more details. // *************************************************************************************** -/** - * @file CmdAddVIA1.cc - * @author Jianrong Su - * @brief Command to add VIA1 connections between M2 and M1 layers - * @version 1.0 - * @date 2025-06-30 - */ - -#include "ShellCmd.hh" -#include "log/Log.hh" -#include "iPNP.hh" -#include "iPNPApi.hh" -#include - -namespace ipnp { - - CmdAddVIA1::CmdAddVIA1(const char* cmd_name) : TclCmd(cmd_name) { - auto* config_option = new TclStringOption("-config", 0, ""); - addOption(config_option); + +#include "tcl_ipnp.h" + +#include "ipnp_api.hh" +#include "tcl_util.h" +#include "tool_manager.h" + +namespace tcl { + +CmdRunPnp::CmdRunPnp(const char* cmd_name) : TclCmd(cmd_name) +{ + auto* config_option = new TclStringOption("-config", 1, nullptr); + addOption(config_option); +} + +unsigned CmdRunPnp::check() +{ + TclOption* config_option = getOptionOrArg("-config"); + LOG_FATAL_IF(!config_option); + return 1; +} + +unsigned CmdRunPnp::exec() +{ + if (!check()) { + return 0; } - unsigned CmdAddVIA1::check() { - TclOption* config_option = getOptionOrArg("-config"); - - if (config_option) { - auto* config_file = config_option->getStringVal(); - if (!std::filesystem::exists(config_file)) { - LOG_ERROR << "Configuration file not found: " << config_file; - return 0; - } - } - return 1; // check success + TclOption* config_option = getOptionOrArg("-config"); + std::string config_file = config_option->getStringVal(); + + std::cout << "Running iPNP with config: " << config_file << std::endl; + + bool success = iplf::tmInst->autoRunPNP(config_file); + + if (success) { + std::cout << "iPNP execution completed successfully" << std::endl; + } else { + std::cout << "iPNP execution failed" << std::endl; } - unsigned CmdAddVIA1::exec() { - if (!check()) { - return 0; - } + return success ? 1 : 0; +} - TclOption* config_option = getOptionOrArg("-config"); - - if (config_option) { - auto* config_file = config_option->getStringVal(); +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (iPNPApi::getInstance()) { - LOG_ERROR << "An existing iPNP instance was found. It will be replaced."; - delete iPNPApi::getInstance(); - iPNPApi::setInstance(nullptr); - } +CmdAddVIA1::CmdAddVIA1(const char* cmd_name) : TclCmd(cmd_name) +{ + auto* config_option = new TclStringOption(TCL_CONFIG, 0, ""); + addOption(config_option); +} - LOG_INFO << "Initializing iPNP with configuration: " << config_file; - auto* new_instance = new ipnp::iPNP(config_file); - iPNPApi::setInstance(new_instance); - } +unsigned CmdAddVIA1::check() +{ + TclOption* file_name_option = getOptionOrArg(TCL_CONFIG); + LOG_FATAL_IF(!file_name_option); - auto* ipnp = iPNPApi::getInstance(); + return 1; // check success +} - LOG_INFO << "Adding VIA1 connections between M2 and M1 layers..."; +unsigned CmdAddVIA1::exec() +{ + if (!check()) { + return 0; + } - ipnp->connect_M2_M1(); + TclOption* config_option = getOptionOrArg(TCL_CONFIG); - std::string output_def_path; - if (ipnp->get_config() && !ipnp->get_config()->get_output_def_path().empty()) { - output_def_path = ipnp->get_config()->get_output_def_path(); - LOG_INFO << "DEF output path read from configuration file: " << output_def_path; - } else { - output_def_path = "./output.def"; - LOG_ERROR << "DEF output path not found in configuration file, using default path."; - } + if (config_option) { + auto* config_file = config_option->getStringVal(); - ipnp->writeIdbToDef(output_def_path); + PNPApiInst->connect_M2_M1(config_file); LOG_INFO << "VIA1 connections added successfully."; - - return 1; } -} // namespace ipnp \ No newline at end of file + return 1; +} + +} // namespace tcl diff --git a/src/operation/iPNP/source/module/tcl-cmd/ShellCmd.hh b/src/interface/tcl/tcl_ipnp/tcl_ipnp.h similarity index 65% rename from src/operation/iPNP/source/module/tcl-cmd/ShellCmd.hh rename to src/interface/tcl/tcl_ipnp/tcl_ipnp.h index f8df8888f5050b638f5c637961da9dfcc36a2f36..1668b5db859bccb5fa2e98b8c7223b84483249ad 100644 --- a/src/operation/iPNP/source/module/tcl-cmd/ShellCmd.hh +++ b/src/interface/tcl/tcl_ipnp/tcl_ipnp.h @@ -14,40 +14,18 @@ // // See the Mulan PSL v2 for more details. // *************************************************************************************** -/** - * @file ShellCmd.hh - * @author Jianrong Su - * @brief - * @version 1.0 - * @date 2025-06-30 - */ - #pragma once #include "ScriptEngine.hh" -#include "iPNP.hh" -#include "PNPConfig.hh" - -namespace ipnp { +#include "tcl_definition.h" -using ieda::ScriptEngine; using ieda::TclCmd; -using ieda::TclCmds; -using ieda::TclDoubleListOption; -using ieda::TclDoubleOption; -using ieda::TclEncodeResult; -using ieda::TclIntListOption; -using ieda::TclIntOption; -using ieda::TclOption; -using ieda::TclStringListListOption; -using ieda::TclStringListOption; -using ieda::TclStringOption; -using ieda::TclSwitchOption; -// Function to register commands +namespace tcl { -class CmdRunPnp : public TclCmd { -public: +class CmdRunPnp : public TclCmd +{ + public: explicit CmdRunPnp(const char* cmd_name); ~CmdRunPnp() override = default; @@ -55,8 +33,9 @@ public: unsigned exec() override; }; -class CmdAddVIA1 : public TclCmd { -public: +class CmdAddVIA1 : public TclCmd +{ + public: explicit CmdAddVIA1(const char* cmd_name); ~CmdAddVIA1() override = default; @@ -64,4 +43,4 @@ public: unsigned exec() override; }; -} // namespace ipnp +} // namespace tcl diff --git a/src/interface/tcl/tcl_ipnp/tcl_register_pnp.h b/src/interface/tcl/tcl_ipnp/tcl_register_pnp.h new file mode 100644 index 0000000000000000000000000000000000000000..0ce15b825f25d3724cc71a40ae1f63156e9949da --- /dev/null +++ b/src/interface/tcl/tcl_ipnp/tcl_register_pnp.h @@ -0,0 +1,35 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once + +#include "ScriptEngine.hh" +#include "UserShell.hh" +#include "tcl_ipnp.h" + +using namespace ieda; + +namespace tcl { + +int registerCmdPNP() +{ + registerTclCmd(CmdRunPnp, "run_pnp"); + registerTclCmd(CmdAddVIA1, "add_via1"); + + return EXIT_SUCCESS; +} + +} // namespace tcl \ No newline at end of file diff --git a/src/interface/tcl/tcl_irt/CMakeLists.txt b/src/interface/tcl/tcl_irt/CMakeLists.txt index 141ef5a937d49385fd2877728867898fd67b2612..868f5b8a693dc57713ca9883ee684f7c31e79aa6 100644 --- a/src/interface/tcl/tcl_irt/CMakeLists.txt +++ b/src/interface/tcl/tcl_irt/CMakeLists.txt @@ -2,6 +2,7 @@ add_library(tcl_irt ${HOME_INTERFACE}/tcl/tcl_irt/src/tcl_clear_def.cpp ${HOME_INTERFACE}/tcl/tcl_irt/src/tcl_destroy_rt.cpp ${HOME_INTERFACE}/tcl/tcl_irt/src/tcl_init_rt.cpp + ${HOME_INTERFACE}/tcl/tcl_irt/src/tcl_output_db_json.cpp ${HOME_INTERFACE}/tcl/tcl_irt/src/tcl_run_egr.cpp ${HOME_INTERFACE}/tcl/tcl_irt/src/tcl_run_rt.cpp ) diff --git a/src/interface/tcl/tcl_irt/include/tcl_register_irt.h b/src/interface/tcl/tcl_irt/include/tcl_register_irt.h index d69cf15746d4255f5df9d929bea3289cd2b6aee6..eba952afad111f64addacc2bb9e989c5adb10ba3 100644 --- a/src/interface/tcl/tcl_irt/include/tcl_register_irt.h +++ b/src/interface/tcl/tcl_irt/include/tcl_register_irt.h @@ -27,6 +27,7 @@ int registerCmdRT() registerTclCmd(TclClearDef, "clear_def"); registerTclCmd(TclDestroyRT, "destroy_rt"); registerTclCmd(TclInitRT, "init_rt"); + registerTclCmd(TclOutputDBJson, "output_db_json"); registerTclCmd(TclRunEGR, "run_egr"); registerTclCmd(TclRunRT, "run_rt"); return EXIT_SUCCESS; diff --git a/src/interface/tcl/tcl_irt/include/tcl_rt.h b/src/interface/tcl/tcl_irt/include/tcl_rt.h index b8f74dcecbb8020798ecf671bcfd7b116d41bcec..16d09ea861f1069cd489593684b067a81b565924 100644 --- a/src/interface/tcl/tcl_irt/include/tcl_rt.h +++ b/src/interface/tcl/tcl_irt/include/tcl_rt.h @@ -62,6 +62,20 @@ class TclInitRT : public TclCmd std::vector> _config_list; }; +class TclOutputDBJson : public TclCmd +{ + public: + explicit TclOutputDBJson(const char* cmd_name); + ~TclOutputDBJson() override = default; + + unsigned check() override { return 1; }; + + unsigned exec() override; + + private: + std::vector> _config_list; +}; + class TclRunEGR : public TclCmd { public: diff --git a/src/interface/tcl/tcl_irt/src/tcl_init_rt.cpp b/src/interface/tcl/tcl_irt/src/tcl_init_rt.cpp index 2480258f6eff4df2ec083e1e9f3fb536cb9e1ff5..cccee9c2e123997a7e22fbf0d69d644b812fd517 100644 --- a/src/interface/tcl/tcl_irt/src/tcl_init_rt.cpp +++ b/src/interface/tcl/tcl_irt/src/tcl_init_rt.cpp @@ -34,6 +34,8 @@ TclInitRT::TclInitRT(const char* cmd_name) : TclCmd(cmd_name) _config_list.push_back(std::make_pair("-top_routing_layer", ValueType::kString)); // int32_t output_inter_result; // optional _config_list.push_back(std::make_pair("-output_inter_result", ValueType::kInt)); + // int32_t enable_notification; // optional + _config_list.push_back(std::make_pair("-enable_notification", ValueType::kInt)); // int32_t enable_timing; // optional _config_list.push_back(std::make_pair("-enable_timing", ValueType::kInt)); // int32_t enable_fast_mode; // optional diff --git a/src/interface/tcl/tcl_irt/src/tcl_output_db_json.cpp b/src/interface/tcl/tcl_irt/src/tcl_output_db_json.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e80b7426efeddea9b9c6785f51326f2ad73f96d --- /dev/null +++ b/src/interface/tcl/tcl_irt/src/tcl_output_db_json.cpp @@ -0,0 +1,45 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#include "RTInterface.hpp" +#include "tcl_rt.h" +#include "tcl_util.h" + +namespace tcl { + +// public + +TclOutputDBJson::TclOutputDBJson(const char* cmd_name) : TclCmd(cmd_name) +{ + _config_list.push_back(std::make_pair("-stage", ValueType::kString)); + _config_list.push_back(std::make_pair("-json_file_path", ValueType::kString)); + + TclUtil::addOption(this, _config_list); +} + +unsigned TclOutputDBJson::exec() +{ + if (!check()) { + return 0; + } + std::map config_map = TclUtil::getConfigMap(this, _config_list); + RTI.outputDBJson(config_map); + return 1; +} + +// private + +} // namespace tcl diff --git a/src/interface/tcl/tcl_notification/CMakeLists.txt b/src/interface/tcl/tcl_notification/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..80a1aa40a95d4300580038d6f3072efd09b6422a --- /dev/null +++ b/src/interface/tcl/tcl_notification/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library(tcl_notification + ${HOME_INTERFACE}/tcl/tcl_notification/src/tcl_init_notification.cpp +) + +target_link_libraries(tcl_notification + PRIVATE + tcl_util + notification +) + +target_include_directories(tcl_notification + PUBLIC + ${HOME_INTERFACE}/tcl/tcl_notification/include +) diff --git a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAGroup.hpp b/src/interface/tcl/tcl_notification/include/tcl_notification.h similarity index 71% rename from src/operation/iRT/source/module/layer_assigner/la_data_manager/LAGroup.hpp rename to src/interface/tcl/tcl_notification/include/tcl_notification.h index 099e3c9440149adbff3346294e0891a70ab53534..f9a50a15c9f0a1cad9cc9b39e740ffabce080671 100644 --- a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAGroup.hpp +++ b/src/interface/tcl/tcl_notification/include/tcl_notification.h @@ -16,23 +16,22 @@ // *************************************************************************************** #pragma once -#include "LayerCoord.hpp" +#include "tcl_util.h" -namespace irt { +namespace tcl { -class LAGroup +class TclInitNotification : public TclCmd { public: - LAGroup() = default; - ~LAGroup() = default; - // getter - std::vector& get_coord_list() { return _coord_list; } - // setter - void set_coord_list(const std::vector& coord_list) { _coord_list = coord_list; } - // function + explicit TclInitNotification(const char* cmd_name); + ~TclInitNotification() override = default; + + unsigned check() override { return 1; }; + + unsigned exec() override; private: - std::vector _coord_list; + std::vector> _config_list; }; -} // namespace irt +} // namespace tcl diff --git a/src/interface/tcl/tcl_notification/include/tcl_register_notification.h b/src/interface/tcl/tcl_notification/include/tcl_register_notification.h new file mode 100644 index 0000000000000000000000000000000000000000..53359789a9fad32d3ef9edfea506aeab324b93d5 --- /dev/null +++ b/src/interface/tcl/tcl_notification/include/tcl_register_notification.h @@ -0,0 +1,31 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once + +#include "tcl_notification.h" + +using namespace ieda; + +namespace tcl { + +int registerCmdNotification() +{ + registerTclCmd(TclInitNotification, "init_notification"); + return EXIT_SUCCESS; +} + +} // namespace tcl diff --git a/src/interface/tcl/tcl_notification/src/tcl_init_notification.cpp b/src/interface/tcl/tcl_notification/src/tcl_init_notification.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0fa0dd5fc025fb8ed65dc87e3e646ad95aec1db0 --- /dev/null +++ b/src/interface/tcl/tcl_notification/src/tcl_init_notification.cpp @@ -0,0 +1,62 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#include "tcl_notification.h" +#include "NotificationUtility.h" +#include +#include + +namespace tcl { + +// public + +TclInitNotification::TclInitNotification(const char* cmd_name) : TclCmd(cmd_name) +{ + // This command doesn't require any parameters as it uses environment variables + // But we can add optional parameters if needed in the future +} + +unsigned TclInitNotification::exec() +{ + if (!check()) { + return 0; + } + + // Initialize notification utility with environment variable validation + bool is_notify_init = ieda::NotificationUtility::getInstance().initialize( + std::getenv("IEDA_ECOS_NOTIFICATION_URL") ? std::getenv("IEDA_ECOS_NOTIFICATION_URL") : "", + std::getenv("ECOS_TASK_ID") ? std::getenv("ECOS_TASK_ID") : "", + std::getenv("ECOS_PROJECT_ID") ? std::getenv("ECOS_PROJECT_ID") : "", + std::getenv("ECOS_TASK_TYPE") ? std::getenv("ECOS_TASK_TYPE") : "" + ); + + // Log the result using the same format as the original implementation + if (is_notify_init) { + std::cout << "[INFO] NotificationUtility initialized successfully with : " + << (std::getenv("IEDA_ECOS_NOTIFICATION_URL") ? std::getenv("IEDA_ECOS_NOTIFICATION_URL") : "null") << " " + << (std::getenv("ECOS_TASK_ID") ? std::getenv("ECOS_TASK_ID") : "null") << " " + << (std::getenv("ECOS_PROJECT_ID") ? std::getenv("ECOS_PROJECT_ID") : "null") << " " + << (std::getenv("ECOS_TASK_TYPE") ? std::getenv("ECOS_TASK_TYPE") : "null") << std::endl; + } else { + std::cout << "[WARN] NotificationUtility initialization failed due to missing environment variables" << std::endl; + } + + return 1; +} + +// private + +} // namespace tcl diff --git a/src/interface/tcl/tcl_register.h b/src/interface/tcl/tcl_register.h index d66fbe16b91f54d04da9847985a66dbbe4dc2421..6f5adebea4ef23e3c6166782b706de96aac74ed4 100644 --- a/src/interface/tcl/tcl_register.h +++ b/src/interface/tcl/tcl_register.h @@ -33,13 +33,13 @@ #include "tcl_flow.h" #include "tcl_register_config.h" #include "tcl_register_cts.h" -#include "tcl_register_idrc.h" #include "tcl_register_eco.h" #include "tcl_register_eval.h" #include "tcl_register_feature.h" #include "tcl_register_flow.h" #include "tcl_register_fp.h" #include "tcl_register_idb.h" +#include "tcl_register_idrc.h" #include "tcl_register_inst.h" #include "tcl_register_irt.h" #include "tcl_register_no.h" @@ -49,6 +49,9 @@ #include "tcl_register_report.h" #include "tcl_register_sta.h" #include "tcl_register_to.h" +#include "tcl_register_vec.h" +#include "tcl_register_pnp.h" +#include "tcl_register_notification.h" #ifdef CONTEST #include "tcl_register_contest.h" @@ -114,6 +117,13 @@ int registerCommands() registerCmdECO(); + registerCmdVectorization(); + + /// PNP + registerCmdPNP(); + + registerCmdNotification(); + #ifdef CONTEST registerCmdContest(); #endif diff --git a/src/interface/tcl/tcl_vec/CMakeLists.txt b/src/interface/tcl/tcl_vec/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4e48a4043402399ade5fb50a0c129c06a4975c4 --- /dev/null +++ b/src/interface/tcl/tcl_vec/CMakeLists.txt @@ -0,0 +1,17 @@ +AUX_SOURCE_DIRECTORY(./ TCL_VEC_SRC) + +add_library(tcl_vec + ${TCL_VEC_SRC} +) + +target_link_libraries(tcl_vec + PUBLIC + tcl + shell-cmd + ivec_api +) + +target_include_directories(tcl_vec + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/src/interface/tcl/tcl_vec/tcl_register_vec.h b/src/interface/tcl/tcl_vec/tcl_register_vec.h new file mode 100644 index 0000000000000000000000000000000000000000..977a91edbbcc0ed86094f69a839e0968c60f71d2 --- /dev/null +++ b/src/interface/tcl/tcl_vec/tcl_register_vec.h @@ -0,0 +1,43 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @File Name: tcl_eco.h + * @Brief : + * @Author : Yell (12112088@qq.com) + * @Version : 1.0 + * @Creat Date : 2024-08-26 + * + */ +#include "ScriptEngine.hh" +#include "UserShell.hh" +#include "tcl_vec.h" + +using namespace ieda; + +namespace tcl { + +int registerCmdVectorization() +{ + registerTclCmd(CmdVecLayoutPatchs, "layout_patchs"); + registerTclCmd(CmdVecLayoutGraph, "layout_graph"); + registerTclCmd(CmdVecFeature, "generate_vectors"); + + return EXIT_SUCCESS; +} + +} // namespace tcl \ No newline at end of file diff --git a/src/interface/tcl/tcl_vec/tcl_vec.cpp b/src/interface/tcl/tcl_vec/tcl_vec.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8943287687c5b6e82018dfdf4c9cf6d39a00abb8 --- /dev/null +++ b/src/interface/tcl/tcl_vec/tcl_vec.cpp @@ -0,0 +1,170 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @File Name: tcl_eco.cpp + * @Brief : + * @Author : Yell (12112088@qq.com) + * @Version : 1.0 + * @Creat Date : 2024-08-26 + * + */ +#include "tcl_vec.h" + +#include + +#include "vec_api.h" + +namespace tcl { +/** + * type : shape, pattern + * default type : shape + */ +CmdVecLayoutPatchs::CmdVecLayoutPatchs(const char* cmd_name) : TclCmd(cmd_name) +{ + auto* option = new TclStringOption(TCL_PATH, 1, nullptr); + addOption(option); +} + +unsigned CmdVecLayoutPatchs::check() +{ + TclOption* option = getOptionOrArg(TCL_PATH); + LOG_FATAL_IF(!option); + + return 1; +} + +unsigned CmdVecLayoutPatchs::exec() +{ + if (!check()) { + return 0; + } + + TclOption* option = getOptionOrArg(TCL_PATH); + if (option != nullptr) { + auto path_option = option->getStringVal(); + std::string path = path_option == nullptr ? "./layout_patchs.csv" : path_option; + + ivec::VectorizationApi vec_api; + vec_api.buildVectorizationLayoutData(path); + } + + return 1; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CmdVecLayoutGraph::CmdVecLayoutGraph(const char* cmd_name) : TclCmd(cmd_name) +{ + auto* option = new TclStringOption(TCL_PATH, 1, nullptr); + addOption(option); +} + +unsigned CmdVecLayoutGraph::check() +{ + TclOption* option = getOptionOrArg(TCL_PATH); + LOG_FATAL_IF(!option); + + return 1; +} + +unsigned CmdVecLayoutGraph::exec() +{ + if (!check()) { + return 0; + } + + TclOption* option = getOptionOrArg(TCL_PATH); + if (option != nullptr) { + auto path_option = option->getStringVal(); + std::string path = path_option == nullptr ? "./layout_graph.json" : path_option; + + ivec::VectorizationApi vec_api; + vec_api.buildVectorizationGraphData(path); + } + + return 1; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CmdVecFeature::CmdVecFeature(const char* cmd_name) : TclCmd(cmd_name) +{ + auto* dir_option = new TclStringOption(TCL_DIRECTORY, 1, nullptr); + addOption(dir_option); + + auto* row_step_option = new TclIntOption(TCL_PATCH_ROW_STEP, 0, 9); + addOption(row_step_option); + + auto* col_step_option = new TclIntOption(TCL_PATCH_COL_STEP, 0, 9); + addOption(col_step_option); +} + +unsigned CmdVecFeature::check() +{ + TclOption* dir_option = getOptionOrArg(TCL_DIRECTORY); + LOG_FATAL_IF(!dir_option); + + TclOption* row_step_option = getOptionOrArg(TCL_PATCH_ROW_STEP); + if (row_step_option && row_step_option->getIntVal() <= 0) { + LOG_ERROR << "patch_row_step must be positive"; + return 0; + } + + TclOption* col_step_option = getOptionOrArg(TCL_PATCH_COL_STEP); + if (col_step_option && col_step_option->getIntVal() <= 0) { + LOG_ERROR << "patch_col_step must be positive"; + return 0; + } + + return 1; +} + +unsigned CmdVecFeature::exec() +{ + if (!check()) { + return 0; + } + + TclOption* dir_option = getOptionOrArg(TCL_DIRECTORY); + if (dir_option != nullptr) { + auto path_option = dir_option->getStringVal(); + std::string path = path_option == nullptr ? "./vectors" : path_option; + + int patch_row_step = 9; + TclOption* row_step_option = getOptionOrArg(TCL_PATCH_ROW_STEP); + if (row_step_option != nullptr) { + patch_row_step = row_step_option->getIntVal(); + } + + int patch_col_step = 9; + TclOption* col_step_option = getOptionOrArg(TCL_PATCH_COL_STEP); + if (col_step_option != nullptr) { + patch_col_step = col_step_option->getIntVal(); + } + + ivec::VectorizationApi vec_api; + vec_api.buildVectorizationFeature(path, patch_row_step, patch_col_step); + } + + return 1; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace tcl diff --git a/src/interface/tcl/tcl_vec/tcl_vec.h b/src/interface/tcl/tcl_vec/tcl_vec.h new file mode 100644 index 0000000000000000000000000000000000000000..e6c25a2bde77320acf7e73419aa0ebd2372369be --- /dev/null +++ b/src/interface/tcl/tcl_vec/tcl_vec.h @@ -0,0 +1,81 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @File Name: tcl_eco.h + * @Brief : + * @Author : Yell (12112088@qq.com) + * @Version : 1.0 + * @Creat Date : 2024-08-26 + * + */ + +#include + +#include "ScriptEngine.hh" +#include "tcl_definition.h" + +using ieda::TclCmd; +using ieda::TclIntOption; +using ieda::TclOption; +using ieda::TclStringOption; + +namespace tcl { + +class CmdVecLayoutPatchs : public TclCmd +{ + public: + explicit CmdVecLayoutPatchs(const char* cmd_name); + ~CmdVecLayoutPatchs() override = default; + + unsigned check() override; + unsigned exec() override; + + private: + // private function + // private data +}; + +class CmdVecLayoutGraph : public TclCmd +{ + public: + explicit CmdVecLayoutGraph(const char* cmd_name); + ~CmdVecLayoutGraph() override = default; + + unsigned check() override; + unsigned exec() override; + + private: + // private function + // private data +}; + +class CmdVecFeature : public TclCmd +{ + public: + explicit CmdVecFeature(const char* cmd_name); + ~CmdVecFeature() override = default; + + unsigned check() override; + unsigned exec() override; + + private: + // private function + // private data +}; + +} // namespace tcl \ No newline at end of file diff --git a/src/operation/iCTS/README.md b/src/operation/iCTS/README.md index e193439ffc0c89b0c1552cd867a7d2171a406a29..53a8a26d973bbf044091178dd6729aefd0b2106a 100644 --- a/src/operation/iCTS/README.md +++ b/src/operation/iCTS/README.md @@ -1,3 +1,60 @@ -# iCTS 功能文档 +# iCTS: Clock Tree Synthesis -## TBD + +## 1. Overview + +Currently, iCTS supports clock tree construction under given constraints. Currently, iCTS takes DME and Slew-Aware as the basic framework and integrates multiple types of constraints for clock tree design. Due to the inability to obtain upstream Slew information in the bottom-up process of DME, +The downstream chained propagation will bring a large error. iCTS introduces the timing backward propagation method and performs timing propagation at the wire level during the buffer insertion stage to correct the insertion delay of the wire load unit. +iCTS uses a more accurate timing model for the estimation and propagation of timing information and constructs the clock tree with the goal of minimizing the design cost. + +### Constraints + +The constraints that iCTS can support are shown in the following table, where the constraint names correspond to the Config parameter names + +| Constraint Name | Constraint Level | +| :-------------: | :--------------: | +| skew_bound | Hard | +| max_buf_tran | Hard | +| max_sink_tran | Hard | +| max_cap | Soft | +| max_fanout | Hard | +| max_length | Soft | + +### Timing Models + +iCTS currently uses the PERI interconnect model as the slew calculation method for interconnects and the Elmore model as the delay calculation method for interconnects. For the insertion delay of buffers, the lookup table method (Lut) is used, which includes extensions of some methods, as shown in the following table. + +| Model | Scenario | Extension | +| :---: | :------------------------------------------------------: | :------------------------------------------------------: | +| PERI | Calculation and propagation of interconnect slew | Formula calculation, timing backward propagation correction | +| Elmore | Calculation of interconnect delay | Formula calculation | +| Unit RC | Conversion of the load capacitance and resistance of interconnects based on the unit capacitance and resistance | Formula calculation | +| Lut | Calculation of buffer insertion delay and unit slew propagation | Bilinear interpolation method, multiple linear fitting model, machine learning model | + +### Goals + +Under the premise of meeting the design constraints as much as possible, for scenarios with multiple buffering schemes, iCTS will adopt the scheme with the minimum design cost for clock tree design. The current measurement methods are as follows: + +* Prefer the buffering scheme with a smaller size that meets the timing constraints. +* For the case of continuous buffer insertion to balance the clock skew, in order to simplify the complexity of timing calculation and propagation, consider using the same buffer and perform timing balancing at a uniform wire length interval. At this stage, the buffering scheme that minimizes the increase in cell area is preferred. + +## 2. Multi-Clock Balance + +iCTS can support multi-clock design. First, a clock tree is constructed for each clock one by one to form the basic clock tree result. The clock skew of the top-level node is analyzed through the timing evaluation of iSTA, and finally, timing balancing is performed according to the design requirements. + +## 3. Support Extensions + +### Multiple Buffer Types + +iCTS supports clock tree design based on multiple buffer types (currently excluding inverters) and selects buffers using the strategy in [Goals](#Goals) during the buffer insertion process. This feature can be set in the `buffer_type` parameter in Config. + +### Clustering to Reduce Scale + +iCTS supports using the clustering method (K-Means) to reduce the running time of large-scale nets. For nets with more than 3000 registers, iCTS will automatically execute the K-Means algorithm and divide them into 50 clusters for local clock tree construction. After completing the local construction, the top-level clock tree is merged. Both the local construction and the top-level clock tree construction use the same clock tree algorithm. + +During the K-Means clustering process, we set the initial number of iterations. In each iteration, we record the total register load capacitance of each cluster and consider the clustering result with a smaller variance of capacitance between clusters for clock tree construction. + +### Machine Learning Models + +iCTS supports the invocation of Python models and methods based on Cython. Currently, the encapsulated Linear, XGBoost, CatBoost models, and basic plotting methods of Matplotlib are available. You can specify the compilation option `SYS_PYTHON3_VERSION` to specify the system Python version, +And by turning on the `PY_MODEL` option, C++ and Python interaction can be achieved. In this mode, the timing-related Lut process will use machine learning models. \ No newline at end of file diff --git a/src/operation/iCTS/source/module/evaluator/EvalNet.hh b/src/operation/iCTS/source/module/evaluator/EvalNet.hh index 9e067b76a406bfd55bb39cd0fbdb8490a40d445d..ce513fbb8daaf20bfa0e9da4ad68ff4413e7bc2a 100644 --- a/src/operation/iCTS/source/module/evaluator/EvalNet.hh +++ b/src/operation/iCTS/source/module/evaluator/EvalNet.hh @@ -23,6 +23,7 @@ #include #include #include +#include #include "CTSAPI.hh" #include "CtsConfig.hh" diff --git a/src/operation/iCTS/source/solver/tools/balance_clustering/BalanceClustering.hh b/src/operation/iCTS/source/solver/tools/balance_clustering/BalanceClustering.hh index 83b46cda7777bb18bc5db5162255d1a4af059b35..c9e8452cedeedbd138fa626bc0d5a0d5ed3eacdb 100644 --- a/src/operation/iCTS/source/solver/tools/balance_clustering/BalanceClustering.hh +++ b/src/operation/iCTS/source/solver/tools/balance_clustering/BalanceClustering.hh @@ -21,6 +21,7 @@ #pragma once #include #include +#include #include "Pin.hh" diff --git a/src/operation/iDRC/README.md b/src/operation/iDRC/README.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b514640976bb016435fd1490279e009014022c5f 100644 --- a/src/operation/iDRC/README.md +++ b/src/operation/iDRC/README.md @@ -0,0 +1,84 @@ +# iDRC: Design Rule Check + +## 1. Overview + +iDRC is a design rule check tool in the iEDA toolchain. Currently, it supports design rule checks for each Metal layer and Cut layer under the 28nm process. The main design rule checks implemented include: short circuit violation check, metal minimum spacing check, minimum width check, minimum area check, hole area check, minimum step (MinStep) check, via enclosure related checks, metal minimum end-of-line (EOL) spacing check, metal minimum notch spacing check, metal minimum jog spacing check, metal minimum corner fill spacing check, and Cut layer minimum spacing related checks. + +## 2. Supported Check Types +### Shape Type Rules +Implements checks for non-Spacing type rules, mainly including checks for MinStep, Width, Area, and Enclosure related rules; +| Check Type | Introduction | +| :-----------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Minimum Step (MinStep) Rule | This rule requires that the outer edge of the metal line cannot have a consecutive number of edges whose side length is smaller than the specified value in the TechFile and exceeds the limit specified in the TechFile; as shown in Figure 1.1 | +| Via Enclosure Rule | The via enclosure rule stipulates the minimum distance between the metal on the upper and lower layers of a certain Cut and the edge of the Cut. Exceeding these distances will result in an enclosure violation, as shown in Figure 1.2 | +| Minimum Width Rule | The minimum width rule is used to constrain the interior facing edge distance (Distance of interior facing edge) of the conductor pattern in the layout, as shown in Figure 1.3(a). It stipulates that the interior facing edge distance of the conductor pattern must not be smaller than the minimum width parameter value specified in the TechFile, including the length of the conductor, the width of the conductor, and the interior diagonal width of the conductor, as shown in (b), (c), and (d) in Figure 1.3. | +| Minimum Area Rule | The minimum area rule stipulates that the conductor area of each process layer cannot be smaller than the minimum area parameter value specified in the TechFile, as shown by the Area indication in the left figure of Figure 1.4 | +| Minimum Hole Area Rule | The minimum enclosed area stipulates that the hole area formed by the conductor enclosure cannot be smaller than the minimum area parameter value specified in the TechFile, as shown by the Enclosed Area indication in the right figure of Figure 1.4. | + +
+ +​ Figure 1.1 Check Object Corresponding to the Minimum Step Rule + +
+ +​ Figure 1.2 Check Object Corresponding to the Via Enclosure Rule + +
+ +​ Figure 1.3 Interior Facing Edge Distance of Conductor Pattern (Check Object Corresponding to the Minimum Width Rule) + +
+ +​ Figure 1.4 Left: Area of Conductor Pattern (Check Object Corresponding to the Minimum Area Rule) + +​ Right: Hole Area Surrounded by Conductor Pattern (Check Object Corresponding to the Minimum Enclosed Area Rule) + +### Spacing Type Rules +| Term | Term Explanation | +| :-----------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Short Circuit Violation | When the conductor geometries belonging to different nets overlap in any form, a short circuit will occur. For example, the line segments (Wire) belonging to different nets, the Pins and vias belonging to different nets, the contact between the net pattern and the obstacle Block are not allowed and are regarded as short circuit violations, as shown in Figure 1.5. | +| Metal Minimum Spacing Rule | The minimum spacing rule can be understood as the exterior facing edge distance (Distance of exterior facing edge) between the conductor patterns in the layout must not be smaller than the minimum spacing parameter value of the current process layer specified in the TechFile. The exterior facing edge distance between conductors, as shown in Figure 1.2(a), the spacing rules include checking the spacing between conductors in the X direction, Y direction, and corner spacing, as shown in Figure 1.6. | +| Metal Minimum End-of-Line (EOL) Spacing Rule | This rule requires that no other metal lines can overlap with the area at the end of the metal line required in the TechFile; the possible size of the area is affected by factors such as the length of the adjacent edge of the end-of-line (EOL), whether there are vias nearby, and adjacent metal lines, as shown in Figure 1.7. | +| Metal Minimum Notch Spacing Rule | This rule requires that the bottom length of the notch formed by the metal line under the conditions specified in the TechFile must not be smaller than the specified value, as shown in Figure 1.8. | +| Metal Minimum Jog Spacing Rule | This rule requires certain specific spacing requirements between some metals existing between a wider metal line and its adjacent metal line with a Parallel Run Length length that meets the requirements of the TechFile, as shown in Figure 1.9. | +| Metal Minimum CornerFill Spacing Rule | This rule requires that when there is a notch-shaped area at the corner of the outer edge of the metal line that meets the requirements of the TechFile, a virtual piece of metal is created at the notch, and the spacing between the virtual metal and other metals is checked, as shown in Figure 1.10. | +| Cut Minimum Spacing Rule | This rule requires that the spacing between any two Cuts in the same Cut layer cannot be smaller than the specified value. Although the Spacing calculation of the Cut layer is generally defaulted to the edge-to-edge Euclidean distance, in some cases, it will change due to certain fields in the rule. In some cases, the maximum projected lengths of the two in the X and Y directions will be used instead of the Euclidean distance to calculate the Spacing, as shown in Figure 1.11. | + +
+ +​ Figure 1.5 Short Circuit Violation + +
+ +​ Figure 1.6 Schematic Diagram of the Exterior Facing Edge Spacing of the Conductor Pattern (Check Object Corresponding to the Minimum Spacing Rule) + +
+ +​ Figure 1.7 Check Object Corresponding to the Metal Minimum End-of-Line (EOL) Spacing Rule + +
+ +​ Figure 1.8 Check Object Corresponding to the Metal Minimum Notch Spacing Rule + +
+ +​ Figure 1.9 Check Object Corresponding to the Metal Minimum Jog Spacing Rule + +
+ +​ Figure 1.10 Check Object Corresponding to the Metal Minimum CornerFill Spacing Rule + +
+ +​ Figure 1.11 Check Object Corresponding to the Cut Minimum Spacing Rule + +## Design Requirements and Goals + +> *Describe requirements and goals.* + +* **iDRC needs to support reading DEF files for design rule checks**: In the EDA toolchain, DEF files play an important role in the process of connecting different tools and exchanging data. As a DRC tool, it should support the application scenario of reading DEF files for DRC checks. iDRC obtains the graphic information and process rule information of the layout by reading DEF files and related LEF files through iDB. Based on the data information of DEF and LEF, it realizes various types of checks supporting 28nm process rules. + +* **iDRC needs to support the design rule check mode interacting with iRT**: The design rule check result is an important evaluation for the routing tool iRT. Based on the design rule check result, iRT can optimize and iterate the routing result. Therefore, iDRC should provide an interaction interface with iRT. iDRC should support conducting design rule checks from the iRT routing result and feeding back the check result to the operation process of iRT. + +## Check Result Reports +iDRC provides two forms of report files: global report and detailed report. The global report file is given in text form and contains the number of violations of various rules; the detailed report file contains detailed information of each violation, the marked box of the violation (indicating the specific location of the violation on the layout), the type of violation, layer information, etc., and supports reading and viewing using a visual interface. \ No newline at end of file diff --git a/src/operation/iDRC/interface/CMakeLists.txt b/src/operation/iDRC/interface/CMakeLists.txt index 7b8a4bb61f1074b3c0d4e38a3fef0c449bb072fe..c09539b5d9bc9c028f687df0837a81a54338af7c 100644 --- a/src/operation/iDRC/interface/CMakeLists.txt +++ b/src/operation/iDRC/interface/CMakeLists.txt @@ -1,8 +1,8 @@ -if(DEBUG_IDRC_INTERFACE) - message(STATUS "DRC: DEBUG_IDRC_INTERFACE") +if(DEBUG_IDRC_INTERFACE) + message(STATUS "DRC: DEBUG_IDRC_INTERFACE") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "DRC: RELEASE_IDRC_INTERFACE") + message(STATUS "DRC: RELEASE_IDRC_INTERFACE") set(CMAKE_BUILD_TYPE "Release") endif() @@ -12,11 +12,12 @@ add_library(idrc_interface target_link_libraries(idrc_interface PRIVATE - idrc_source - idm + idrc_source + idm + notification ) target_include_directories(idrc_interface PUBLIC - ${IDRC_INTERFACE} + ${IDRC_INTERFACE} ) diff --git a/src/operation/iDRC/interface/DRCInterface.cpp b/src/operation/iDRC/interface/DRCInterface.cpp index 50cd83d7832a3119f89fa4f80dec61e999b11d53..d99b2ebab9c5f97908d9c3807aede931b6465af7 100644 --- a/src/operation/iDRC/interface/DRCInterface.cpp +++ b/src/operation/iDRC/interface/DRCInterface.cpp @@ -20,6 +20,7 @@ #include "DataManager.hpp" #include "GDSPlotter.hpp" #include "Monitor.hpp" +#include "NotificationUtility.h" #include "RuleValidator.hpp" #include "feature_manager.h" #include "idm.h" @@ -82,7 +83,7 @@ void DRCInterface::initDRC(std::map config_map, bool enab void DRCInterface::checkDef() { std::map> type_violation_map; - for (ids::Violation& ids_violation : getViolationList(buildEnvShapeList(), buildResultShapeList())) { + for (ids::Violation& ids_violation : getViolationList(buildEnvShapeList(), buildResultShapeList(), {}, {})) { type_violation_map[ids_violation.violation_type].push_back(ids_violation); } printSummary(type_violation_map); @@ -117,7 +118,9 @@ void DRCInterface::destroyDRC() } std::vector DRCInterface::getViolationList(const std::vector& ids_env_shape_list, - const std::vector& ids_result_shape_list) + const std::vector& ids_result_shape_list, + const std::set& ids_check_type_set, + const std::vector& ids_check_region_list) { std::vector drc_env_shape_list; drc_env_shape_list.reserve(ids_env_shape_list.size()); @@ -129,8 +132,16 @@ std::vector DRCInterface::getViolationList(const std::vector drc_check_type_set; + for (std::string ids_check_type : ids_check_type_set) { + drc_check_type_set.insert(GetViolationTypeByName()(ids_check_type)); + } + std::vector drc_check_region_list; + for (const ids::Shape& ids_check_region : ids_check_region_list) { + drc_check_region_list.push_back(convertToDRCShape(ids_check_region)); + } std::vector ids_violation_list; - for (Violation& violation : DRCRV.verify(drc_env_shape_list, drc_result_shape_list)) { + for (Violation& violation : DRCRV.verify(drc_env_shape_list, drc_result_shape_list, drc_check_type_set, drc_check_region_list)) { ids::Violation ids_violation; ids_violation.violation_type = GetViolationTypeName()(violation.get_violation_type()); ids_violation.ll_x = violation.get_ll_x(); @@ -349,6 +360,39 @@ void DRCInterface::wrapRoutingDesignRule(RoutingLayer& routing_layer, idb::IdbLa minimum_area_rule.min_area = idb_layer->get_area(); exist_rule_set.insert(ViolationType::kMinimumArea); } + // MinimumCutRule + { + std::vector& minimum_cut_rule_list = routing_layer.get_minimum_cut_rule_list(); + if (!idb_layer->get_lef58_minimum_cut().empty()) { + for (std::shared_ptr& idb_minimum_cut : idb_layer->get_lef58_minimum_cut()) { + MinimumCutRule minimum_cut_rule; + if (idb_minimum_cut.get()->get_num_cuts().has_value()) { + minimum_cut_rule.num_cuts = idb_minimum_cut.get()->get_num_cuts().value(); + } else { + for (const idb::routinglayer::Lef58MinimumCut::CutClass& idb_cut_class : idb_minimum_cut.get()->get_cut_classes()) { + if (idb_cut_class.get_class_name() == "VSINGLECUT") { + minimum_cut_rule.num_cuts = idb_cut_class.get_num_cuts(); + break; + } + } + } + minimum_cut_rule.width = idb_minimum_cut.get()->get_width(); + minimum_cut_rule.has_within_cut_distance = idb_minimum_cut.get()->get_within_cut_distance().has_value(); + if (idb_minimum_cut.get()->get_within_cut_distance().has_value()) { + minimum_cut_rule.within_cut_distance = idb_minimum_cut.get()->get_within_cut_distance().value(); + } + minimum_cut_rule.has_from_above = idb_minimum_cut.get()->get_orient() == idb::routinglayer::Lef58MinimumCut::Orient::kFromAbove ? true : false; + minimum_cut_rule.has_from_below = idb_minimum_cut.get()->get_orient() == idb::routinglayer::Lef58MinimumCut::Orient::kFromBelow ? true : false; + minimum_cut_rule.has_length = idb_minimum_cut.get()->get_length().has_value(); + if (idb_minimum_cut.get()->get_length().has_value()) { + minimum_cut_rule.length = idb_minimum_cut.get()->get_length().value().get_length(); + minimum_cut_rule.distance = idb_minimum_cut.get()->get_length().value().get_distance(); + } + minimum_cut_rule_list.push_back(minimum_cut_rule); + } + exist_rule_set.insert(ViolationType::kMinimumCut); + } + } // MinimumWidthRule { MinimumWidthRule& minimum_width_rule = routing_layer.get_minimum_width_rule(); @@ -956,12 +1000,10 @@ void DRCInterface::printSummary(std::map>& type_violation_map) { std::vector& routing_layer_list = DRCDM.getDatabase().get_routing_layer_list(); - std::vector& cut_layer_list = DRCDM.getDatabase().get_cut_layer_list(); std::map>& cut_to_adjacent_routing_map = DRCDM.getDatabase().get_cut_to_adjacent_routing_map(); std::string& temp_directory_path = DRCDM.getConfig().temp_directory_path; std::vector& idb_net_list = dmInst->get_idb_def_service()->get_design()->get_net_list()->get_net_list(); - std::vector violation_json_list; for (auto& [type, violation_list] : type_violation_map) { for (ids::Violation& violation : violation_list) { @@ -975,12 +1017,17 @@ void DRCInterface::outputViolationJson(std::mapget_net_name()); + if (net_idx != -1) { + violation_json["net"].push_back(idb_net_list[net_idx]->get_net_name()); + } else { + violation_json["net"].push_back("obs"); + } } violation_json_list.push_back(violation_json); } } - std::ofstream* violation_json_file = DRCUTIL.getOutputFileStream(DRCUTIL.getString(temp_directory_path, "violation_map.json")); + std::string violation_json_file_path = DRCUTIL.getString(temp_directory_path, "violation_map.json"); + std::ofstream* violation_json_file = DRCUTIL.getOutputFileStream(violation_json_file_path); (*violation_json_file) << violation_json_list; DRCUTIL.closeFileStream(violation_json_file); } diff --git a/src/operation/iDRC/interface/DRCInterface.hpp b/src/operation/iDRC/interface/DRCInterface.hpp index 9176ee11edc24f8d826a7f125ba76b021a50f5c3..dbf043ba8e8bcbf877e01ce5ac1b51953c238e7b 100644 --- a/src/operation/iDRC/interface/DRCInterface.hpp +++ b/src/operation/iDRC/interface/DRCInterface.hpp @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include @@ -58,7 +59,8 @@ class DRCInterface void initDRC(std::map config_map, bool enable_quiet); void checkDef(); void destroyDRC(); - std::vector getViolationList(const std::vector& ids_env_shape_list, const std::vector& ids_result_shape_list); + std::vector getViolationList(const std::vector& ids_env_shape_list, const std::vector& ids_result_shape_list, + const std::set& ids_check_type_set, const std::vector& ids_check_region_list); #endif #endif diff --git a/src/operation/iDRC/source/CMakeLists.txt b/src/operation/iDRC/source/CMakeLists.txt index c90490883fc5ec4c4a16679addb1551d6ebbc413..655834a99fdd39ef21006812be43632d77ff7082 100644 --- a/src/operation/iDRC/source/CMakeLists.txt +++ b/src/operation/iDRC/source/CMakeLists.txt @@ -12,7 +12,7 @@ add_library(idrc_source INTERFACE) target_link_libraries(idrc_source INTERFACE - idrc_data_manager - idrc_module - idrc_toolkit + idrc_data_manager + idrc_module + idrc_toolkit ) diff --git a/src/operation/iDRC/source/data_manager/CMakeLists.txt b/src/operation/iDRC/source/data_manager/CMakeLists.txt index c22b382bf028ea1e4e9737da883eb514c6675d1a..3f2922052f5b33eabc64d35b46781c9695fca598 100644 --- a/src/operation/iDRC/source/data_manager/CMakeLists.txt +++ b/src/operation/iDRC/source/data_manager/CMakeLists.txt @@ -1,8 +1,8 @@ -if(DEBUG_IDRC_DATA_MANAGER) - message(STATUS "DRC: DEBUG_IDRC_DATA_MANAGER") +if(DEBUG_IDRC_DATA_MANAGER) + message(STATUS "DRC: DEBUG_IDRC_DATA_MANAGER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "DRC: RELEASE_IDRC_DATA_MANAGER") + message(STATUS "DRC: RELEASE_IDRC_DATA_MANAGER") set(CMAKE_BUILD_TYPE "Release") endif() @@ -10,15 +10,15 @@ add_library(idrc_data_manager ${IDRC_DATA_MANAGER}/DataManager.cpp ) -target_link_libraries(idrc_data_manager +target_link_libraries(idrc_data_manager PUBLIC - idrc_toolkit + idrc_toolkit ) -target_include_directories(idrc_data_manager +target_include_directories(idrc_data_manager PUBLIC - ${IDRC_DATA_MANAGER}/advance - ${IDRC_DATA_MANAGER}/basic - ${IDRC_DATA_MANAGER}/design_rule - ${IDRC_DATA_MANAGER} + ${IDRC_DATA_MANAGER}/advance + ${IDRC_DATA_MANAGER}/basic + ${IDRC_DATA_MANAGER}/design_rule + ${IDRC_DATA_MANAGER} ) diff --git a/src/operation/iDRC/source/data_manager/advance/RoutingLayer.hpp b/src/operation/iDRC/source/data_manager/advance/RoutingLayer.hpp index f1b0d19c8efe8b911c78638c9d0b33b005d32d6e..977af32428634a81c62e8a33ced09ff03eeacd7d 100644 --- a/src/operation/iDRC/source/data_manager/advance/RoutingLayer.hpp +++ b/src/operation/iDRC/source/data_manager/advance/RoutingLayer.hpp @@ -24,6 +24,7 @@ #include "MinHoleRule.hpp" #include "MinStepRule.hpp" #include "MinimumAreaRule.hpp" +#include "MinimumCutRule.hpp" #include "MinimumWidthRule.hpp" #include "NonsufficientMetalOverlapRule.hpp" #include "NotchSpacingRule.hpp" @@ -48,6 +49,7 @@ class RoutingLayer MaximumWidthRule& get_maximum_width_rule() { return _maximum_width_rule; } MinHoleRule& get_min_hole_rule() { return _min_hole_rule; } MinimumAreaRule& get_minimum_area_rule() { return _minimum_area_rule; } + std::vector& get_minimum_cut_rule_list() { return _minimum_cut_rule_list; } MinimumWidthRule& get_minimum_width_rule() { return _minimum_width_rule; } MinStepRule& get_min_step_rule() { return _min_step_rule; } NonsufficientMetalOverlapRule& get_nonsufficient_metal_overlap_rule() { return _nonsufficient_metal_overlap_rule; } @@ -73,6 +75,7 @@ class RoutingLayer MaximumWidthRule _maximum_width_rule; MinHoleRule _min_hole_rule; MinimumAreaRule _minimum_area_rule; + std::vector _minimum_cut_rule_list; MinimumWidthRule _minimum_width_rule; MinStepRule _min_step_rule; NonsufficientMetalOverlapRule _nonsufficient_metal_overlap_rule; diff --git a/src/operation/iDRC/source/data_manager/advance/ViolationType.hpp b/src/operation/iDRC/source/data_manager/advance/ViolationType.hpp index 914a01be86a11d4ac1aed5f95fb7232c4d4b9fd8..ef1402fb1e0862c58e0f5cb5ff5cda69dfcb40cf 100644 --- a/src/operation/iDRC/source/data_manager/advance/ViolationType.hpp +++ b/src/operation/iDRC/source/data_manager/advance/ViolationType.hpp @@ -25,6 +25,7 @@ enum class ViolationType kNone, kAdjacentCutSpacing, kCornerFillSpacing, + kCornerSpacing, kCutEOLSpacing, kCutShort, kDifferentLayerCutSpacing, @@ -65,6 +66,9 @@ struct GetViolationTypeName case ViolationType::kCornerFillSpacing: violation_type_name = "corner_fill_spacing"; break; + case ViolationType::kCornerSpacing: + violation_type_name = "corner_spacing"; + break; case ViolationType::kCutEOLSpacing: violation_type_name = "cut_eol_spacing"; break; @@ -151,8 +155,8 @@ struct GetViolationTypeByName violation_type = ViolationType::kAdjacentCutSpacing; } else if (violation_type_name == "corner_fill_spacing") { violation_type = ViolationType::kCornerFillSpacing; - } else if (violation_type_name == "corner_fill_spacing") { - violation_type = ViolationType::kCornerFillSpacing; + } else if (violation_type_name == "corner_spacing") { + violation_type = ViolationType::kCornerSpacing; } else if (violation_type_name == "cut_eol_spacing") { violation_type = ViolationType::kCutEOLSpacing; } else if (violation_type_name == "cut_short") { diff --git a/src/operation/iDRC/source/data_manager/design_rule/MinimumCutRule.hpp b/src/operation/iDRC/source/data_manager/design_rule/MinimumCutRule.hpp index ef24d7c89494c42355b50051036f260f2f23e863..18a073494604b7625b48714fd436c6fa85fb41bf 100644 --- a/src/operation/iDRC/source/data_manager/design_rule/MinimumCutRule.hpp +++ b/src/operation/iDRC/source/data_manager/design_rule/MinimumCutRule.hpp @@ -25,6 +25,15 @@ class MinimumCutRule public: MinimumCutRule() = default; ~MinimumCutRule() = default; + int32_t num_cuts = -1; + int32_t width = -1; + bool has_within_cut_distance = false; + /**/ int32_t within_cut_distance = -1; + bool has_from_above = false; + bool has_from_below = false; + bool has_length = false; + /**/ int32_t length = -1; + /**/ int32_t distance = -1; }; } // namespace idrc diff --git a/src/operation/iDRC/source/module/CMakeLists.txt b/src/operation/iDRC/source/module/CMakeLists.txt index 8213c6df6e2e10b6a93a01e02de6d2294fa25bc8..c5a31bef3e86fc3aeb628c30baf59d11a75d8d69 100644 --- a/src/operation/iDRC/source/module/CMakeLists.txt +++ b/src/operation/iDRC/source/module/CMakeLists.txt @@ -3,8 +3,8 @@ add_subdirectory(${IDRC_MODULE}/rule_validator) add_library(idrc_module INTERFACE) -target_link_libraries(idrc_module +target_link_libraries(idrc_module INTERFACE - idrc_gds_plotter - idrc_rule_validator + idrc_gds_plotter + idrc_rule_validator ) diff --git a/src/operation/iDRC/source/module/gds_plotter/CMakeLists.txt b/src/operation/iDRC/source/module/gds_plotter/CMakeLists.txt index 3cf3d3d61df418e9062252d9c5474180458ae7e1..0b3074f3a30b25b6a246b6bdcd62f9858414327c 100644 --- a/src/operation/iDRC/source/module/gds_plotter/CMakeLists.txt +++ b/src/operation/iDRC/source/module/gds_plotter/CMakeLists.txt @@ -1,8 +1,8 @@ -if(DEBUG_IDRC_GDS_PLOTTER) - message(STATUS "DRC: DEBUG_IDRC_GDS_PLOTTER") +if(DEBUG_IDRC_GDS_PLOTTER) + message(STATUS "DRC: DEBUG_IDRC_GDS_PLOTTER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "DRC: RELEASE_IDRC_GDS_PLOTTER") + message(STATUS "DRC: RELEASE_IDRC_GDS_PLOTTER") set(CMAKE_BUILD_TYPE "Release") endif() @@ -11,15 +11,15 @@ add_library(idrc_gds_plotter ${IDRC_MODULE}/gds_plotter/GDSPlotter.cpp ) -target_link_libraries(idrc_gds_plotter +target_link_libraries(idrc_gds_plotter PUBLIC - idrc_data_manager - idrc_module - idrc_toolkit + idrc_data_manager + idrc_module + idrc_toolkit ) -target_include_directories(idrc_gds_plotter +target_include_directories(idrc_gds_plotter PUBLIC - ${IDRC_MODULE}/gds_plotter/gp_data_manager - ${IDRC_MODULE}/gds_plotter + ${IDRC_MODULE}/gds_plotter/gp_data_manager + ${IDRC_MODULE}/gds_plotter ) diff --git a/src/operation/iDRC/source/module/gds_plotter/GDSPlotter.cpp b/src/operation/iDRC/source/module/gds_plotter/GDSPlotter.cpp index f4c730ab074a3c4d38ac8980075ca41a6004710f..6a35899d063dce2dd0ebfa399e8286efca7f53b1 100644 --- a/src/operation/iDRC/source/module/gds_plotter/GDSPlotter.cpp +++ b/src/operation/iDRC/source/module/gds_plotter/GDSPlotter.cpp @@ -95,6 +95,9 @@ GPDataType GDSPlotter::convertGPDataType(ViolationType violation_type) case ViolationType::kCornerFillSpacing: gp_data_type = GPDataType::kCornerFillSpacing; break; + case ViolationType::kCornerSpacing: + gp_data_type = GPDataType::kCornerSpacing; + break; case ViolationType::kCutEOLSpacing: gp_data_type = GPDataType::kCutEOLSpacing; break; @@ -224,6 +227,7 @@ void GDSPlotter::buildGraphLypFile() {GPDataType::kResultShape, false}, {GPDataType::kAdjacentCutSpacing, false}, {GPDataType::kCornerFillSpacing, false}, + {GPDataType::kCornerSpacing, false}, {GPDataType::kCutEOLSpacing, false}, {GPDataType::kCutShort, false}, {GPDataType::kDifferentLayerCutSpacing, false}, diff --git a/src/operation/iDRC/source/module/gds_plotter/gp_data_manager/GPDataType.hpp b/src/operation/iDRC/source/module/gds_plotter/gp_data_manager/GPDataType.hpp index b27d3b2ea60d47c37e8d4f206edce330b3a471a6..f67dc983b87e5cf406a41ee0e5fe670582f4717f 100644 --- a/src/operation/iDRC/source/module/gds_plotter/gp_data_manager/GPDataType.hpp +++ b/src/operation/iDRC/source/module/gds_plotter/gp_data_manager/GPDataType.hpp @@ -27,6 +27,7 @@ enum class GPDataType kResultShape, kAdjacentCutSpacing, kCornerFillSpacing, + kCornerSpacing, kCutEOLSpacing, kCutShort, kDifferentLayerCutSpacing, @@ -73,6 +74,9 @@ struct GetGPDataTypeName case GPDataType::kCornerFillSpacing: data_type_name = "corner_fill_spacing"; break; + case GPDataType::kCornerSpacing: + data_type_name = "corner_spacing"; + break; case GPDataType::kCutEOLSpacing: data_type_name = "cut_eol_spacing"; break; diff --git a/src/operation/iDRC/source/module/rule_validator/CMakeLists.txt b/src/operation/iDRC/source/module/rule_validator/CMakeLists.txt index 36026da4ebee38ccbc6731f6df9a4a2ae798d8e9..e9964b40f838ec0edb886e4ef4dd855e3be27186 100644 --- a/src/operation/iDRC/source/module/rule_validator/CMakeLists.txt +++ b/src/operation/iDRC/source/module/rule_validator/CMakeLists.txt @@ -2,8 +2,8 @@ if(DEBUG_IDRC_RULE_VALIDATOR) message(STATUS "DRC: DEBUG_IDRC_RULE_VALIDATOR") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "DRC: RELEASE_IDRC_RULE_VALIDATOR") - set(CMAKE_BUILD_TYPE "Release") + message(STATUS "DRC: RELEASE_IDRC_RULE_VALIDATOR") + set(CMAKE_BUILD_TYPE "Release") endif() add_library(idrc_rule_validator @@ -11,6 +11,7 @@ add_library(idrc_rule_validator ${IDRC_MODULE}/rule_validator/RuleValidator.cpp ${IDRC_MODULE}/rule_validator/rv_design_rule/AdjacentCutSpacing.cpp ${IDRC_MODULE}/rule_validator/rv_design_rule/CornerFillSpacing.cpp + ${IDRC_MODULE}/rule_validator/rv_design_rule/CornerSpacing.cpp ${IDRC_MODULE}/rule_validator/rv_design_rule/CutEOLSpacing.cpp ${IDRC_MODULE}/rule_validator/rv_design_rule/CutShort.cpp ${IDRC_MODULE}/rule_validator/rv_design_rule/DifferentLayerCutSpacing.cpp @@ -36,15 +37,15 @@ add_library(idrc_rule_validator ${IDRC_MODULE}/rule_validator/rv_design_rule/SameLayerCutSpacing.cpp ) -target_link_libraries(idrc_rule_validator +target_link_libraries(idrc_rule_validator PUBLIC - idrc_data_manager - idrc_module - idrc_toolkit + idrc_data_manager + idrc_module + idrc_toolkit ) -target_include_directories(idrc_rule_validator +target_include_directories(idrc_rule_validator PUBLIC - ${IDRC_MODULE}/rule_validator/rv_data_manager - ${IDRC_MODULE}/rule_validator + ${IDRC_MODULE}/rule_validator/rv_data_manager + ${IDRC_MODULE}/rule_validator ) diff --git a/src/operation/iDRC/source/module/rule_validator/RuleValidator.cpp b/src/operation/iDRC/source/module/rule_validator/RuleValidator.cpp index ebe26cb0ceee1029365af37fde67df86387dbf67..fc7976af524d4cfafeee0837d50c8e159983be76 100644 --- a/src/operation/iDRC/source/module/rule_validator/RuleValidator.cpp +++ b/src/operation/iDRC/source/module/rule_validator/RuleValidator.cpp @@ -48,14 +48,14 @@ void RuleValidator::destroyInst() } // function - -std::vector RuleValidator::verify(std::vector& drc_env_shape_list, std::vector& drc_result_shape_list) +std::vector RuleValidator::verify(std::vector& drc_env_shape_list, std::vector& drc_result_shape_list, + std::set& drc_check_type_set, std::vector& drc_check_region_list) { Monitor monitor; DRCLOG.info(Loc::current(), "Starting..."); - RVModel rv_model = initRVModel(drc_env_shape_list, drc_result_shape_list); + RVModel rv_model = initRVModel(drc_env_shape_list, drc_result_shape_list, drc_check_type_set, drc_check_region_list); setRVComParam(rv_model); - buildRVModel(rv_model); + buildRVBoxList(rv_model); verifyRVModel(rv_model); // debugVerifyRVModelByGolden(rv_model); buildViolationList(rv_model); @@ -70,11 +70,14 @@ std::vector RuleValidator::verify(std::vector& drc_env_shap RuleValidator* RuleValidator::_rv_instance = nullptr; -RVModel RuleValidator::initRVModel(std::vector& drc_env_shape_list, std::vector& drc_result_shape_list) +RVModel RuleValidator::initRVModel(std::vector& drc_env_shape_list, std::vector& drc_result_shape_list, + std::set& drc_check_type_set, std::vector& drc_check_region_list) { RVModel rv_model; rv_model.set_drc_env_shape_list(drc_env_shape_list); rv_model.set_drc_result_shape_list(drc_result_shape_list); + rv_model.set_drc_check_type_set(drc_check_type_set); + rv_model.set_drc_check_region_list(drc_check_region_list); return rv_model; } @@ -87,14 +90,14 @@ void RuleValidator::setRVComParam(RVModel& rv_model) * box_size, expand_size */ // clang-format off - RVComParam rv_com_param(box_size,expand_size); + RVComParam rv_com_param(box_size, expand_size); // clang-format on DRCLOG.info(Loc::current(), "box_size: ", rv_com_param.get_box_size()); DRCLOG.info(Loc::current(), "expand_size: ", rv_com_param.get_expand_size()); rv_model.set_rv_com_param(rv_com_param); } -void RuleValidator::buildRVModel(RVModel& rv_model) +void RuleValidator::buildRVBoxList(RVModel& rv_model) { std::vector& rv_box_list = rv_model.get_rv_box_list(); int32_t box_size = rv_model.get_rv_com_param().get_box_size(); @@ -130,6 +133,7 @@ void RuleValidator::buildRVModel(RVModel& rv_model) rv_box.set_box_idx(grid_x + grid_y * grid_x_size); rv_box.get_box_rect().set_ll(grid_x * box_size + offset_x, grid_y * box_size + offset_y); rv_box.get_box_rect().set_ur((grid_x + 1) * box_size + offset_x, (grid_y + 1) * box_size + offset_y); + rv_box.set_rv_com_param(&rv_model.get_rv_com_param()); } } for (DRCShape& drc_env_shape : rv_model.get_drc_env_shape_list()) { @@ -166,6 +170,10 @@ void RuleValidator::buildRVModel(RVModel& rv_model) } } } + for (RVBox& rv_box : rv_box_list) { + rv_box.set_drc_check_type_set(&rv_model.get_drc_check_type_set()); + rv_box.set_drc_check_region_list(&rv_model.get_drc_check_region_list()); + } for (DRCShape& drc_result_shape : rv_model.get_drc_result_shape_list()) { if (drc_result_shape.get_net_idx() < 0) { DRCLOG.error(Loc::current(), "The drc_result_shape_list exist idx < 0!"); @@ -179,6 +187,7 @@ void RuleValidator::verifyRVModel(RVModel& rv_model) DRCLOG.info(Loc::current(), "Starting..."); #pragma omp parallel for for (RVBox& rv_box : rv_model.get_rv_box_list()) { + buildRVBox(rv_box); if (needVerifying(rv_box)) { buildViolationSet(rv_box); buildViolationList(rv_box); @@ -189,6 +198,47 @@ void RuleValidator::verifyRVModel(RVModel& rv_model) DRCLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); } +void RuleValidator::buildRVBox(RVBox& rv_box) +{ + std::map>& routing_to_adjacent_cut_map = DRCDM.getDatabase().get_routing_to_adjacent_cut_map(); + + std::vector* drc_check_region_list = rv_box.get_drc_check_region_list(); + int32_t expand_size = rv_box.get_rv_com_param()->get_expand_size(); + + if (!drc_check_region_list->empty()) { + std::vector drc_env_shape_list; + std::vector drc_result_shape_list; + for (DRCShape& drc_check_region : *drc_check_region_list) { + PlanarRect searched_rect = DRCUTIL.getEnlargedRect(drc_check_region.get_rect(), expand_size); + std::map> type_layer_idx_map; + { + int32_t layer_idx = drc_check_region.get_layer_idx(); + type_layer_idx_map[true].insert({layer_idx - 1, layer_idx, layer_idx + 1}); + std::vector& cut_layer_idx_list = routing_to_adjacent_cut_map[layer_idx]; + type_layer_idx_map[false].insert(cut_layer_idx_list.begin(), cut_layer_idx_list.end()); + } + for (DRCShape* drc_shape : rv_box.get_drc_env_shape_list()) { + if (DRCUTIL.exist(type_layer_idx_map[drc_shape->get_is_routing()], drc_shape->get_layer_idx()) + && DRCUTIL.isClosedOverlap(searched_rect, drc_shape->get_rect())) { + drc_env_shape_list.push_back(drc_shape); + } + } + for (DRCShape* drc_shape : rv_box.get_drc_result_shape_list()) { + if (DRCUTIL.exist(type_layer_idx_map[drc_shape->get_is_routing()], drc_shape->get_layer_idx()) + && DRCUTIL.isClosedOverlap(searched_rect, drc_shape->get_rect())) { + drc_result_shape_list.push_back(drc_shape); + } + } + } + std::sort(drc_env_shape_list.begin(), drc_env_shape_list.end()); + drc_env_shape_list.erase(std::unique(drc_env_shape_list.begin(), drc_env_shape_list.end()), drc_env_shape_list.end()); + std::sort(drc_result_shape_list.begin(), drc_result_shape_list.end()); + drc_result_shape_list.erase(std::unique(drc_result_shape_list.begin(), drc_result_shape_list.end()), drc_result_shape_list.end()); + rv_box.set_drc_env_shape_list(drc_env_shape_list); + rv_box.set_drc_result_shape_list(drc_result_shape_list); + } +} + bool RuleValidator::needVerifying(RVBox& rv_box) { if (rv_box.get_drc_result_shape_list().empty()) { @@ -217,85 +267,99 @@ void RuleValidator::buildViolationSet(RVBox& rv_box) void RuleValidator::verifyRVBox(RVBox& rv_box) { - std::set& exist_rule_set = DRCDM.getDatabase().get_exist_rule_set(); - - if (DRCUTIL.exist(exist_rule_set, ViolationType::kAdjacentCutSpacing)) { + if (needVerifying(rv_box, ViolationType::kAdjacentCutSpacing)) { verifyAdjacentCutSpacing(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kCornerFillSpacing)) { + if (needVerifying(rv_box, ViolationType::kCornerFillSpacing)) { verifyCornerFillSpacing(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kCutEOLSpacing)) { + if (needVerifying(rv_box, ViolationType::kCornerSpacing)) { + verifyCornerSpacing(rv_box); + } + if (needVerifying(rv_box, ViolationType::kCutEOLSpacing)) { verifyCutEOLSpacing(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kCutShort)) { + if (needVerifying(rv_box, ViolationType::kCutShort)) { verifyCutShort(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kDifferentLayerCutSpacing)) { + if (needVerifying(rv_box, ViolationType::kDifferentLayerCutSpacing)) { verifyDifferentLayerCutSpacing(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kEnclosure)) { + if (needVerifying(rv_box, ViolationType::kEnclosure)) { verifyEnclosure(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kEnclosureEdge)) { + if (needVerifying(rv_box, ViolationType::kEnclosureEdge)) { verifyEnclosureEdge(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kEnclosureParallel)) { + if (needVerifying(rv_box, ViolationType::kEnclosureParallel)) { verifyEnclosureParallel(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kEndOfLineSpacing)) { + if (needVerifying(rv_box, ViolationType::kEndOfLineSpacing)) { verifyEndOfLineSpacing(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kFloatingPatch)) { + if (needVerifying(rv_box, ViolationType::kFloatingPatch)) { verifyFloatingPatch(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kJogToJogSpacing)) { + if (needVerifying(rv_box, ViolationType::kJogToJogSpacing)) { verifyJogToJogSpacing(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kMaximumWidth)) { + if (needVerifying(rv_box, ViolationType::kMaximumWidth)) { verifyMaximumWidth(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kMaxViaStack)) { + if (needVerifying(rv_box, ViolationType::kMaxViaStack)) { verifyMaxViaStack(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kMetalShort)) { + if (needVerifying(rv_box, ViolationType::kMetalShort)) { verifyMetalShort(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kMinHole)) { + if (needVerifying(rv_box, ViolationType::kMinHole)) { verifyMinHole(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kMinimumArea)) { + if (needVerifying(rv_box, ViolationType::kMinimumArea)) { verifyMinimumArea(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kMinimumCut)) { + if (needVerifying(rv_box, ViolationType::kMinimumCut)) { verifyMinimumCut(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kMinimumWidth)) { + if (needVerifying(rv_box, ViolationType::kMinimumWidth)) { verifyMinimumWidth(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kMinStep)) { + if (needVerifying(rv_box, ViolationType::kMinStep)) { verifyMinStep(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kNonsufficientMetalOverlap)) { + if (needVerifying(rv_box, ViolationType::kNonsufficientMetalOverlap)) { verifyNonsufficientMetalOverlap(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kNotchSpacing)) { + if (needVerifying(rv_box, ViolationType::kNotchSpacing)) { verifyNotchSpacing(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kOffGridOrWrongWay)) { + if (needVerifying(rv_box, ViolationType::kOffGridOrWrongWay)) { verifyOffGridOrWrongWay(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kOutOfDie)) { + if (needVerifying(rv_box, ViolationType::kOutOfDie)) { verifyOutOfDie(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kParallelRunLengthSpacing)) { + if (needVerifying(rv_box, ViolationType::kParallelRunLengthSpacing)) { verifyParallelRunLengthSpacing(rv_box); } - if (DRCUTIL.exist(exist_rule_set, ViolationType::kSameLayerCutSpacing)) { + if (needVerifying(rv_box, ViolationType::kSameLayerCutSpacing)) { verifySameLayerCutSpacing(rv_box); } } +bool RuleValidator::needVerifying(RVBox& rv_box, ViolationType violation_type) +{ + std::set& exist_rule_set = DRCDM.getDatabase().get_exist_rule_set(); + + std::set* drc_check_type_set = rv_box.get_drc_check_type_set(); + + if (drc_check_type_set->empty()) { + return DRCUTIL.exist(exist_rule_set, violation_type); + } else { + return (DRCUTIL.exist(*drc_check_type_set, violation_type) && DRCUTIL.exist(exist_rule_set, violation_type)); + } +} + void RuleValidator::processRVBox(RVBox& rv_box) { std::vector new_violation_list; @@ -975,14 +1039,14 @@ void RuleValidator::debugVerifyRVBoxByGolden(RVBox& rv_box) } else { if (violation_type == ViolationType::kMinHole || violation_type == ViolationType::kMinimumArea) { required_size = static_cast(std::round(std::stod(required) * micron_dbu * micron_dbu)); - } else if (violation_type == ViolationType::kMaxViaStack) { + } else if (violation_type == ViolationType::kMaxViaStack || violation_type == ViolationType::kMinimumCut) { required_size = static_cast(std::round(std::stod(required))); } else { required_size = static_cast(std::round(std::stod(required) * micron_dbu)); } } // 筛选 - if (violation_type == ViolationType::kFloatingPatch || violation_type == ViolationType::kEnclosure || violation_type == ViolationType::kMinimumCut) { + if (violation_type == ViolationType::kFloatingPatch || violation_type == ViolationType::kEnclosure) { continue; } if (violation_net_set.size() == 1 && (*violation_net_set.begin()) == -1) { diff --git a/src/operation/iDRC/source/module/rule_validator/RuleValidator.hpp b/src/operation/iDRC/source/module/rule_validator/RuleValidator.hpp index a96de46f6a10b6aa671b1f60aed8f13792188d0b..117dc4942934a8f44f719204daf4e135067f9a89 100644 --- a/src/operation/iDRC/source/module/rule_validator/RuleValidator.hpp +++ b/src/operation/iDRC/source/module/rule_validator/RuleValidator.hpp @@ -33,7 +33,8 @@ class RuleValidator static RuleValidator& getInst(); static void destroyInst(); // function - std::vector verify(std::vector& drc_env_shape_list, std::vector& drc_result_shape_list); + std::vector verify(std::vector& drc_env_shape_list, std::vector& drc_result_shape_list, + std::set& drc_check_type_set, std::vector& drc_check_region_list); private: // self @@ -46,15 +47,18 @@ class RuleValidator RuleValidator& operator=(const RuleValidator& other) = delete; RuleValidator& operator=(RuleValidator&& other) = delete; // function - RVModel initRVModel(std::vector& drc_env_shape_list, std::vector& drc_result_shape_list); + RVModel initRVModel(std::vector& drc_env_shape_list, std::vector& drc_result_shape_list, std::set& drc_check_type_set, + std::vector& drc_check_region_list); void setRVComParam(RVModel& rv_model); - void buildRVModel(RVModel& rv_model); + void buildRVBoxList(RVModel& rv_model); void verifyRVModel(RVModel& rv_model); + void buildRVBox(RVBox& rv_box); bool needVerifying(RVBox& rv_box); void buildViolationSet(RVBox& rv_box); void verifyRVBox(RVBox& rv_box); void verifyAdjacentCutSpacing(RVBox& rv_box); void verifyCornerFillSpacing(RVBox& rv_box); + void verifyCornerSpacing(RVBox& rv_box); void verifyCutEOLSpacing(RVBox& rv_box); void verifyCutShort(RVBox& rv_box); void verifyDifferentLayerCutSpacing(RVBox& rv_box); @@ -78,6 +82,7 @@ class RuleValidator void verifyOutOfDie(RVBox& rv_box); void verifyParallelRunLengthSpacing(RVBox& rv_box); void verifySameLayerCutSpacing(RVBox& rv_box); + bool needVerifying(RVBox& rv_box, ViolationType violation_type); void processRVBox(RVBox& rv_box); void buildViolationList(RVBox& rv_box); void updateSummary(RVBox& rv_box); diff --git a/src/operation/iDRC/source/module/rule_validator/rv_data_manager/RVBox.hpp b/src/operation/iDRC/source/module/rule_validator/rv_data_manager/RVBox.hpp index c31d6b47c433742117f208c95338dc41aceb9459..ecf60da26c2db54dcadb19844b773da413038827 100644 --- a/src/operation/iDRC/source/module/rule_validator/rv_data_manager/RVBox.hpp +++ b/src/operation/iDRC/source/module/rule_validator/rv_data_manager/RVBox.hpp @@ -22,6 +22,7 @@ #include "RVSummary.hpp" #include "Segment.hpp" #include "Violation.hpp" +#include "RVComParam.hpp" namespace idrc { @@ -33,8 +34,11 @@ class RVBox // getter int32_t get_box_idx() const { return _box_idx; } PlanarRect& get_box_rect() { return _box_rect; } + RVComParam* get_rv_com_param() { return _rv_com_param; } std::vector& get_drc_env_shape_list() { return _drc_env_shape_list; } std::vector& get_drc_result_shape_list() { return _drc_result_shape_list; } + std::set* get_drc_check_type_set() { return _drc_check_type_set; } + std::vector* get_drc_check_region_list() { return _drc_check_region_list; } std::set& get_env_violation_set() { return _env_violation_set; } std::vector& get_violation_list() { return _violation_list; } std::map>& get_type_violation_map() { return _type_violation_map; } @@ -43,8 +47,11 @@ class RVBox // setter void set_box_idx(const int32_t box_idx) { _box_idx = box_idx; } void set_box_rect(const PlanarRect& box_rect) { _box_rect = box_rect; } + void set_rv_com_param(RVComParam* rv_com_param) { _rv_com_param = rv_com_param; } void set_drc_env_shape_list(const std::vector& drc_env_shape_list) { _drc_env_shape_list = drc_env_shape_list; } void set_drc_result_shape_list(const std::vector& drc_result_shape_list) { _drc_result_shape_list = drc_result_shape_list; } + void set_drc_check_type_set(std::set* drc_check_type_set) { _drc_check_type_set = drc_check_type_set; } + void set_drc_check_region_list(std::vector* drc_check_region_list) { _drc_check_region_list = drc_check_region_list; } void set_env_violation_set(const std::set& env_violation_set) { _env_violation_set = env_violation_set; } void set_violation_list(const std::vector& violation_list) { _violation_list = violation_list; } void set_type_violation_map(const std::map>& type_violation_map) @@ -57,12 +64,14 @@ class RVBox } void set_rv_summary(const RVSummary& rv_summary) { _rv_summary = rv_summary; } // function - private: int32_t _box_idx = -1; PlanarRect _box_rect; + RVComParam* _rv_com_param = nullptr; std::vector _drc_env_shape_list; std::vector _drc_result_shape_list; + std::set* _drc_check_type_set; + std::vector* _drc_check_region_list; std::set _env_violation_set; std::vector _violation_list; std::map> _type_violation_map; diff --git a/src/operation/iDRC/source/module/rule_validator/rv_data_manager/RVModel.hpp b/src/operation/iDRC/source/module/rule_validator/rv_data_manager/RVModel.hpp index 5d7df039b2a8d2176e30bcc03eda3289226a8642..5afe490ddd4f1340f7a8f3d285c732bec3a14be6 100644 --- a/src/operation/iDRC/source/module/rule_validator/rv_data_manager/RVModel.hpp +++ b/src/operation/iDRC/source/module/rule_validator/rv_data_manager/RVModel.hpp @@ -30,6 +30,8 @@ class RVModel // getter std::vector& get_drc_env_shape_list() { return _drc_env_shape_list; } std::vector& get_drc_result_shape_list() { return _drc_result_shape_list; } + std::set& get_drc_check_type_set() { return _drc_check_type_set; } + std::vector& get_drc_check_region_list() { return _drc_check_region_list; } RVComParam& get_rv_com_param() { return _rv_com_param; } std::vector& get_rv_box_list() { return _rv_box_list; } std::vector& get_violation_list() { return _violation_list; } @@ -37,14 +39,17 @@ class RVModel // setter void set_drc_env_shape_list(const std::vector& drc_env_shape_list) { _drc_env_shape_list = drc_env_shape_list; } void set_drc_result_shape_list(const std::vector& drc_result_shape_list) { _drc_result_shape_list = drc_result_shape_list; } + void set_drc_check_type_set(const std::set& drc_check_type_set) { _drc_check_type_set = drc_check_type_set; } + void set_drc_check_region_list(const std::vector& drc_check_region_list) { _drc_check_region_list = drc_check_region_list; } void set_rv_com_param(const RVComParam& rv_com_param) { _rv_com_param = rv_com_param; } void set_rv_box_list(const std::vector& rv_box_list) { _rv_box_list = rv_box_list; } void set_violation_list(const std::vector& violation_list) { _violation_list = violation_list; } void set_rv_summary(const RVSummary& rv_summary) { _rv_summary = rv_summary; } - private: std::vector _drc_env_shape_list; std::vector _drc_result_shape_list; + std::set _drc_check_type_set; + std::vector _drc_check_region_list; RVComParam _rv_com_param; std::vector _rv_box_list; std::vector _violation_list; diff --git a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/AdjacentCutSpacing.cpp b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/AdjacentCutSpacing.cpp index 0a6e4e22e2347a1f0b0df0f8b8b7a54259920457..a74609abea8aec4ecd5681c28057340466f45509 100644 --- a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/AdjacentCutSpacing.cpp +++ b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/AdjacentCutSpacing.cpp @@ -20,6 +20,117 @@ namespace idrc { void RuleValidator::verifyAdjacentCutSpacing(RVBox& rv_box) { +#if 0 + /* + 规则: SPACING 0.155 ADJACENTCUTS 3 WITHIN 0.200 ; + */ + struct AdjacentCutSpacingRule // 这是cut spacing的子规则 + { + int32_t cut_spacing = -1; + int32_t adjacent_cuts = -1; + int32_t within = -1; + }; + std::map layer_adjacent_cut_spacing_rule; + for (int32_t i = 1; i <= 4; i++) { + AdjacentCutSpacingRule rule = {310, 3, 400}; + layer_adjacent_cut_spacing_rule[i] = rule; // via2-via5 + } + std::vector& cut_layer_list = DRCDM.getDatabase().get_cut_layer_list(); + std::map>& cut_to_adjacent_routing_map = DRCDM.getDatabase().get_cut_to_adjacent_routing_map(); + + std::map>> cut_net_rect_map; + std::map, bgi::quadratic<16>>> cut_bg_rtree_map; + for (DRCShape* drc_shape : rv_box.get_drc_env_shape_list()) { + if (drc_shape->get_is_routing()) { + continue; + } + cut_net_rect_map[drc_shape->get_layer_idx()][drc_shape->get_net_idx()].push_back(drc_shape->get_rect()); + cut_bg_rtree_map[drc_shape->get_layer_idx()].insert(std::make_pair(DRCUTIL.convertToBGRectInt(drc_shape->get_rect()), drc_shape->get_net_idx())); + } + for (DRCShape* drc_shape : rv_box.get_drc_result_shape_list()) { + if (drc_shape->get_is_routing()) { + continue; + } + cut_net_rect_map[drc_shape->get_layer_idx()][drc_shape->get_net_idx()].push_back(drc_shape->get_rect()); + cut_bg_rtree_map[drc_shape->get_layer_idx()].insert(std::make_pair(DRCUTIL.convertToBGRectInt(drc_shape->get_rect()), drc_shape->get_net_idx())); + } + for (auto& [cut_layer_idx, net_rect_map] : cut_net_rect_map) { + int32_t routing_layer_idx = -1; + { + std::vector& routing_layer_idx_list = cut_to_adjacent_routing_map[cut_layer_idx]; + routing_layer_idx = *std::min_element(routing_layer_idx_list.begin(), routing_layer_idx_list.end()); + } + if (!DRCUTIL.exist(layer_adjacent_cut_spacing_rule, cut_layer_idx)) { + continue; + } + AdjacentCutSpacingRule& curr_rule = layer_adjacent_cut_spacing_rule[cut_layer_idx]; + int32_t cut_spacing = curr_rule.cut_spacing; + int32_t adjacent_cuts = curr_rule.adjacent_cuts; + int32_t within = curr_rule.within; + for (auto& [net_idx, rect_list] : net_rect_map) { + for (PlanarRect& rect : rect_list) { + std::vector> bg_rect_net_pair_list; + { + PlanarRect check_rect = DRCUTIL.getEnlargedRect(rect, within); + cut_bg_rtree_map[cut_layer_idx].query(bgi::intersects(DRCUTIL.convertToBGRectInt(check_rect)), std::back_inserter(bg_rect_net_pair_list)); + } + int32_t adjacent_cut_count = 0; + bool is_inside_spacing = false; + std::vector> env_cut_rect_list; + for (auto& [bg_env_rect, env_net_idx] : bg_rect_net_pair_list) { + PlanarRect env_rect = DRCUTIL.convertToPlanarRect(bg_env_rect); + if (env_rect == rect) { + continue; // 忽略自己 + } + if (DRCUTIL.getEuclideanDistance(rect, env_rect) >= within) { + continue; // 忽略不在within范围内的 + } + if (DRCUTIL.getEuclideanDistance(rect, env_rect) < cut_spacing) { + is_inside_spacing = true; // 在spacing范围内 + } + env_cut_rect_list.push_back(std::make_pair(env_net_idx, env_rect)); + adjacent_cut_count++; + } + if (adjacent_cut_count < adjacent_cuts) { + continue; // 忽略不满足adjacent_cuts的 + } + if (is_inside_spacing == false) { + continue; + } + sort(env_cut_rect_list.begin(), env_cut_rect_list.end(), [&](const std::pair& a, const std::pair& b) { + SortStatus sort_status = SortStatus::kEqual; + double a_dis = DRCUTIL.getEuclideanDistance(rect, a.second); + double b_dis = DRCUTIL.getEuclideanDistance(rect, b.second); + // EuclideanDistance大的优先 + if (sort_status == SortStatus::kEqual) { + if (a_dis > b_dis) { + sort_status = SortStatus::kTrue; + } else if (a_dis < b_dis) { + sort_status = SortStatus::kFalse; + } else { + sort_status = SortStatus::kEqual; + } + } + if (sort_status == SortStatus::kTrue) { + return true; + } else if (sort_status == SortStatus::kFalse) { + return false; + } + return false; + }); + int32_t env_idx = env_cut_rect_list.front().first; + Violation violation; + violation.set_violation_type(ViolationType::kAdjacentCutSpacing); + violation.set_is_routing(true); + violation.set_violation_net_set({net_idx, env_idx}); + violation.set_layer_idx(routing_layer_idx); + violation.set_rect(rect); + violation.set_required_size(cut_spacing); + rv_box.get_violation_list().push_back(violation); + } + } + } +#endif } } // namespace idrc diff --git a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/CornerSpacing.cpp b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/CornerSpacing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a33fb801aaee1c41b0c9701da0f816d7f0c388c --- /dev/null +++ b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/CornerSpacing.cpp @@ -0,0 +1,240 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#include "RuleValidator.hpp" + +namespace idrc { + +void RuleValidator::verifyCornerSpacing(RVBox& rv_box) +{ +#if 0 + /* + PROPERTY LEF58_CORNERSPACING "CORNERSPACING CONVEXCORNER EXCEPTEOL 0.08 + WIDTH 0.00 SPACING 0.10 + WIDTH 0.20 SPACING 0.20 + WIDTH 0.50 SPACING 0.30 ;" ; + */ + // corner to corner rule + struct CornerSpacingRule + { + bool has_convex_corner = false; + bool has_except_eol = false; + int32_t eolwidth = 0; + std::vector> width_spacing_list; + }; + std::map layer_corner_spacing_rule; // M2-M7 + for (int32_t i = 1; i <= 6; i++) { + CornerSpacingRule rule = {true, true, 160, {{0, 200}, {400, 400}, {1000, 600}}}; + layer_corner_spacing_rule[i] = rule; // M2-M7 + } +/////////// +#if 1 // 数据结构定义 + struct PolyInfo + { + int32_t coord_size = -1; + std::vector coord_list; + std::vector convex_corner_list; + std::vector> edge_list; + std::vector edge_length_list; + std::set eol_edge_idx_set; + GTLHolePolyInt gtl_hole_poly; + int32_t poly_info_idx = -1; + }; +#endif + std::vector& routing_layer_list = DRCDM.getDatabase().get_routing_layer_list(); + std::map>& routing_to_adjacent_cut_map = DRCDM.getDatabase().get_routing_to_adjacent_cut_map(); + + std::map>> routing_net_poly_info_map; + { + std::map> routing_net_gtl_poly_set_map; + for (DRCShape* drc_shape : rv_box.get_drc_env_shape_list()) { + if (drc_shape->get_is_routing()) { + routing_net_gtl_poly_set_map[drc_shape->get_layer_idx()][drc_shape->get_net_idx()] += DRCUTIL.convertToGTLRectInt(drc_shape->get_rect()); + } + } + for (DRCShape* drc_shape : rv_box.get_drc_result_shape_list()) { + if (drc_shape->get_is_routing()) { + routing_net_gtl_poly_set_map[drc_shape->get_layer_idx()][drc_shape->get_net_idx()] += DRCUTIL.convertToGTLRectInt(drc_shape->get_rect()); + } + } + for (auto& [routing_layer_idx, net_gtl_poly_set_map] : routing_net_gtl_poly_set_map) { + for (auto& [net_idx, gtl_poly_set] : net_gtl_poly_set_map) { + std::vector gtl_hole_poly_list; + gtl_poly_set.get(gtl_hole_poly_list); + for (GTLHolePolyInt& gtl_hole_poly : gtl_hole_poly_list) { + int32_t coord_size = static_cast(gtl_hole_poly.size()); + if (coord_size < 4) { + continue; + } + std::vector coord_list; + for (auto iter = gtl_hole_poly.begin(); iter != gtl_hole_poly.end(); iter++) { + coord_list.push_back(DRCUTIL.convertToPlanarCoord(*iter)); + } + std::vector convex_corner_list; + std::vector> edge_list; + std::vector edge_length_list; + for (int32_t i = 0; i < coord_size; i++) { + PlanarCoord& pre_coord = coord_list[getIdx(i - 1, coord_size)]; + PlanarCoord& curr_coord = coord_list[i]; + PlanarCoord& post_coord = coord_list[getIdx(i + 1, coord_size)]; + convex_corner_list.push_back(DRCUTIL.isConvexCorner(DRCUTIL.getRotation(gtl_hole_poly), pre_coord, curr_coord, post_coord)); + edge_list.push_back(Segment(pre_coord, curr_coord)); + edge_length_list.push_back(DRCUTIL.getManhattanDistance(pre_coord, curr_coord)); + } + std::set eol_edge_idx_set; + for (int32_t i = 0; i < coord_size; i++) { + if (convex_corner_list[getIdx(i - 1, coord_size)] && convex_corner_list[i]) { + eol_edge_idx_set.insert(i); + } + } + routing_net_poly_info_map[routing_layer_idx][net_idx].emplace_back(coord_size, coord_list, convex_corner_list, edge_list, edge_length_list, + eol_edge_idx_set, gtl_hole_poly); + } + } + } + } + std::map>, bgi::quadratic<16>>> routing_bg_rtree_map; + { + for (auto& [routing_layer_idx, net_poly_info_map] : routing_net_poly_info_map) { + for (auto& [net_idx, poly_info_list] : net_poly_info_map) { + for (int32_t i = 0; i < static_cast(poly_info_list.size()); i++) { + std::vector gtl_rect_list; + gtl::get_max_rectangles(gtl_rect_list, poly_info_list[i].gtl_hole_poly); + for (GTLRectInt& gtl_rect : gtl_rect_list) { + routing_bg_rtree_map[routing_layer_idx].insert(std::make_pair(DRCUTIL.convertToBGRectInt(gtl_rect), std::make_pair(net_idx, i))); + } + poly_info_list[i].poly_info_idx = i; + } + } + } + } + + for (auto& [routing_layer_idx, net_poly_info_map] : routing_net_poly_info_map) { + if (DRCUTIL.exist(layer_corner_spacing_rule, routing_layer_idx) == false) { + continue; // skip layer without corner spacing rule + } + CornerSpacingRule& curr_rule = layer_corner_spacing_rule[routing_layer_idx]; + for (auto& [net_idx, poly_info_list] : net_poly_info_map) { + for (PolyInfo& poly_info : poly_info_list) { + int32_t& coord_size = poly_info.coord_size; + std::vector& coord_list = poly_info.coord_list; + std::vector gtl_rect_list; + gtl::get_max_rectangles(gtl_rect_list, poly_info.gtl_hole_poly); + std::vector rect_list; + std::set eol_edge_idx_set = poly_info.eol_edge_idx_set; + for (GTLRectInt& gtl_rect : gtl_rect_list) { + rect_list.push_back(DRCUTIL.convertToPlanarRect(gtl_rect)); + } + for (int32_t eol_idx = 0; eol_idx < poly_info.convex_corner_list.size(); eol_idx++) { + if (!poly_info.convex_corner_list[eol_idx]) { + continue; // skip non-convex corner + } + if(curr_rule.has_except_eol){ + int32_t eol_width = curr_rule.eolwidth; + int32_t post_eol_idx = getIdx(eol_idx + 1, coord_size); + if((DRCUTIL.exist(eol_edge_idx_set, eol_idx) && poly_info.edge_length_list[eol_idx] < eol_width) || + (DRCUTIL.exist(eol_edge_idx_set, post_eol_idx) && poly_info.edge_length_list[post_eol_idx] < eol_width)) { + continue; // skip if the adjacent edges are shorter than the eol width + } + } + PlanarCoord eol_coord = coord_list[eol_idx]; + PlanarCoord pre_coord = coord_list[getIdx(eol_idx - 1, coord_size)]; + PlanarCoord post_coord = coord_list[getIdx(eol_idx + 1, coord_size)]; + PlanarRect corner_rect = DRCUTIL.getBoundingBox({pre_coord, eol_coord, post_coord}); + Orientation pre_orientation = DRCUTIL.getOrientation(pre_coord, eol_coord); + Orientation post_orientation = DRCUTIL.getOrientation(eol_coord, post_coord); + int32_t max_width = 0; + for (PlanarRect& rect : rect_list) { + if (DRCUTIL.isInside(rect, eol_coord)) { + max_width = std::max(max_width, rect.getWidth()); + } + } + int32_t required_spacing = 0; + for (auto& [width, spacing] : curr_rule.width_spacing_list) { + if (max_width > width) { + required_spacing = spacing; + } + } + PlanarRect check_rect; + if (pre_orientation == Orientation::kNorth && post_orientation == Orientation::kWest) { + check_rect = DRCUTIL.getEnlargedRect(eol_coord, 0, 0, required_spacing, required_spacing); + } else if (pre_orientation == Orientation::kWest && post_orientation == Orientation::kSouth) { + check_rect = DRCUTIL.getEnlargedRect(eol_coord, required_spacing, 0, 0, required_spacing); + } else if (pre_orientation == Orientation::kSouth && post_orientation == Orientation::kEast) { + check_rect = DRCUTIL.getEnlargedRect(eol_coord, required_spacing, required_spacing, 0, 0); + } else if (pre_orientation == Orientation::kEast && post_orientation == Orientation::kNorth) { + check_rect = DRCUTIL.getEnlargedRect(eol_coord, 0, required_spacing, required_spacing, 0); + } else { + DRCLOG.error(Loc::current(), "Unrecognized orientation!"); + } + + std::map> env_net_poly_info_idx_map; + { + std::vector>> bg_rect_net_pair_list; + routing_bg_rtree_map[routing_layer_idx].query(bgi::intersects(DRCUTIL.convertToBGRectInt(check_rect)), std::back_inserter(bg_rect_net_pair_list)); + for (auto& [bg_env_rect, net_poly_info_idx_pair] : bg_rect_net_pair_list) { + env_net_poly_info_idx_map[net_poly_info_idx_pair.first].insert(net_poly_info_idx_pair.second); + } + } + std::map orientation_map = {{Orientation::kEast, Orientation::kWest}, + {Orientation::kWest, Orientation::kEast}, + {Orientation::kSouth, Orientation::kNorth}, + {Orientation::kNorth, Orientation::kSouth}}; + for (auto& [env_net_idx, env_poly_info_idx_set] : env_net_poly_info_idx_map) { + for (int32_t env_poly_info_idx : env_poly_info_idx_set) { + PolyInfo& env_poly_info = net_poly_info_map[env_net_idx][env_poly_info_idx]; + + for (int32_t env_eol_idx = 0; env_eol_idx < env_poly_info.convex_corner_list.size(); env_eol_idx++) { + if (!env_poly_info.convex_corner_list[env_eol_idx]) { + continue; // skip non-convex corner + } + PlanarCoord env_eol_coord = env_poly_info.coord_list[env_eol_idx]; + PlanarCoord env_pre_coord = env_poly_info.coord_list[getIdx(env_eol_idx - 1, env_poly_info.coord_size)]; + PlanarCoord env_post_coord = env_poly_info.coord_list[getIdx(env_eol_idx + 1, env_poly_info.coord_size)]; + if(DRCUTIL.isInside(check_rect, env_eol_coord) == false ) { + continue; + } + if (!(orientation_map[pre_orientation] == DRCUTIL.getOrientation(env_pre_coord, env_eol_coord) + && orientation_map[post_orientation] == DRCUTIL.getOrientation(env_eol_coord, env_post_coord))) { + continue; // skip if the orientation is not matched + } + int32_t x_spacing = std::abs(env_eol_coord.get_x() - eol_coord.get_x()); + int32_t y_spacing = std::abs(env_eol_coord.get_y() - eol_coord.get_y()); + int32_t MAXXY_spacing = std::max(x_spacing, y_spacing); + if (MAXXY_spacing >= required_spacing || MAXXY_spacing == 0) { + continue; // skip if the spacing is not satisfied + } + + PlanarRect violation_rect = DRCUTIL.getBoundingBox({eol_coord, env_eol_coord}); + Violation violation; + violation.set_violation_type(ViolationType::kCornerSpacing); + violation.set_required_size(required_spacing); + violation.set_is_routing(true); + violation.set_violation_net_set({net_idx, env_net_idx}); + violation.set_layer_idx(routing_layer_idx); + violation.set_rect(violation_rect); + rv_box.get_violation_list().push_back(violation); + } + } + } + } + } + } + } +#endif +} + +} // namespace idrc diff --git a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/MaxViaStack.cpp b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/MaxViaStack.cpp index e574f959a846d18cc7d13bc5f262a684e71684de..5c68deff954670d9cc2c529e5c92308076fb2b9f 100644 --- a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/MaxViaStack.cpp +++ b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/MaxViaStack.cpp @@ -65,26 +65,21 @@ void RuleValidator::verifyMaxViaStack(RVBox& rv_box) std::map>> layer_net_stack_rect_map; layer_net_stack_rect_map[cut_layer_idx].push_back(net_stack_rect_pair); for (int32_t curr_cut_layer_idx = cut_layer_idx; curr_cut_layer_idx < top_cut_layer_idx; curr_cut_layer_idx++) { - std::vector> bg_rect_net_pair_list; - { - std::vector stack_rect_list; - for (auto& [net_idx, stack_rect] : layer_net_stack_rect_map[curr_cut_layer_idx]) { - stack_rect_list.push_back(stack_rect); - } - PlanarRect check_rect = DRCUTIL.getBoundingBox(stack_rect_list); + std::map> net_used_rect_set; + for (auto& [net_idx, stack_rect] : layer_net_stack_rect_map[curr_cut_layer_idx]) { + std::vector> bg_rect_net_pair_list; + PlanarRect check_rect = stack_rect; cut_bg_rtree_map[curr_cut_layer_idx + 1].query(bgi::intersects(DRCUTIL.convertToBGRectInt(check_rect)), std::back_inserter(bg_rect_net_pair_list)); - } - if (bg_rect_net_pair_list.empty()) { - break; - } - for (auto& [bg_env_rect, env_net_idx] : bg_rect_net_pair_list) { - PlanarRect env_rect = DRCUTIL.convertToPlanarRect(bg_env_rect); - for (auto& [net_idx, stack_rect] : layer_net_stack_rect_map[curr_cut_layer_idx]) { + for (auto& [bg_env_rect, env_net_idx] : bg_rect_net_pair_list) { + PlanarRect env_rect = DRCUTIL.convertToPlanarRect(bg_env_rect); if (!DRCUTIL.isOpenOverlap(stack_rect, env_rect)) { continue; } + if(DRCUTIL.exist(net_used_rect_set[env_net_idx], env_rect)) { + continue; + } layer_net_stack_rect_map[curr_cut_layer_idx + 1].push_back({env_net_idx, env_rect}); - break; + net_used_rect_set[env_net_idx].insert(env_rect); } } } diff --git a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/MinimumCut.cpp b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/MinimumCut.cpp index 494bc3e8df1bca8506118a07edb1c0cd718247bd..7a0f9fb13cd1bc4a64b2d84e7f169a30fba36477 100644 --- a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/MinimumCut.cpp +++ b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/MinimumCut.cpp @@ -20,6 +20,145 @@ namespace idrc { void RuleValidator::verifyMinimumCut(RVBox& rv_box) { + std::vector& routing_layer_list = DRCDM.getDatabase().get_routing_layer_list(); + std::map>& routing_to_adjacent_cut_map = DRCDM.getDatabase().get_routing_to_adjacent_cut_map(); + std::map>& cut_to_adjacent_routing_map = DRCDM.getDatabase().get_cut_to_adjacent_routing_map(); + + std::map> routing_net_gtl_poly_set_map; + { + for (DRCShape* drc_shape : rv_box.get_drc_env_shape_list()) { + if (drc_shape->get_is_routing()) { + routing_net_gtl_poly_set_map[drc_shape->get_layer_idx()][drc_shape->get_net_idx()] += DRCUTIL.convertToGTLRectInt(drc_shape->get_rect()); + } + } + for (DRCShape* drc_shape : rv_box.get_drc_result_shape_list()) { + if (drc_shape->get_is_routing()) { + routing_net_gtl_poly_set_map[drc_shape->get_layer_idx()][drc_shape->get_net_idx()] += DRCUTIL.convertToGTLRectInt(drc_shape->get_rect()); + } + } + } + std::map, bgi::quadratic<16>>> cut_bg_rtree_map; + { + for (DRCShape* drc_shape : rv_box.get_drc_env_shape_list()) { + if (!drc_shape->get_is_routing()) { + cut_bg_rtree_map[drc_shape->get_layer_idx()].insert(std::make_pair(DRCUTIL.convertToBGRectInt(drc_shape->get_rect()), drc_shape->get_net_idx())); + } + } + for (DRCShape* drc_shape : rv_box.get_drc_result_shape_list()) { + if (!drc_shape->get_is_routing()) { + cut_bg_rtree_map[drc_shape->get_layer_idx()].insert(std::make_pair(DRCUTIL.convertToBGRectInt(drc_shape->get_rect()), drc_shape->get_net_idx())); + } + } + } + for (auto& [routing_layer_idx, net_gtl_poly_set_map] : routing_net_gtl_poly_set_map) { + std::vector& minimum_cut_rule_list = routing_layer_list[routing_layer_idx].get_minimum_cut_rule_list(); + if (minimum_cut_rule_list.empty()) { + continue; + } + std::vector& cut_layer_idx_list = routing_to_adjacent_cut_map[routing_layer_idx]; + int32_t above_cut_layer_idx = *std::max_element(cut_layer_idx_list.begin(), cut_layer_idx_list.end()); + int32_t below_cut_layer_idx = *std::min_element(cut_layer_idx_list.begin(), cut_layer_idx_list.end()); + for (auto& [net_idx, gtl_poly_set] : net_gtl_poly_set_map) { + std::vector gtl_poly_list; + gtl_poly_set.get_polygons(gtl_poly_list); + for (GTLPolyInt& gtl_poly : gtl_poly_list) { + std::vector gtl_rect_list; + gtl::get_max_rectangles(gtl_rect_list, gtl_poly); + for (GTLRectInt& gtl_rect : gtl_rect_list) { + PlanarRect routing_rect = DRCUTIL.convertToPlanarRect(gtl_rect); + for (int32_t rule_idx = minimum_cut_rule_list.size() - 1; rule_idx >= 0; rule_idx--) { + MinimumCutRule& curr_rule = minimum_cut_rule_list[rule_idx]; + if (routing_rect.getWidth() < curr_rule.width) { + continue; + } + std::vector check_cut_layer_idx_list; + if (curr_rule.has_from_above) { + check_cut_layer_idx_list.push_back(above_cut_layer_idx); + } else if (curr_rule.has_from_below) { + check_cut_layer_idx_list.push_back(below_cut_layer_idx); + } else { + check_cut_layer_idx_list = cut_layer_idx_list; + } + std::map>> cut_cut_rect_list_list_map; + if (curr_rule.has_length && routing_rect.getLength() > curr_rule.length) { + std::vector env_gtl_poly_list; + { + GTLPolySetInt env_gtl_poly_set = (gtl_poly - gtl_rect); + env_gtl_poly_set.get_polygons(env_gtl_poly_list); + } + for (GTLPolyInt& env_gtl_poly : env_gtl_poly_list) { + std::vector env_gtl_rect_list; + gtl::get_max_rectangles(env_gtl_rect_list, env_gtl_poly); + for (int32_t cut_layer_idx : check_cut_layer_idx_list) { + std::vector cut_rect_list; + for (GTLRectInt& env_gtl_rect : env_gtl_rect_list) { + std::vector> cut_bg_rect_net_pair_list; + cut_bg_rtree_map[cut_layer_idx].query(bgi::intersects(DRCUTIL.convertToBGRectInt(env_gtl_rect)), + std::back_inserter(cut_bg_rect_net_pair_list)); + for (auto& [bg_env_rect, env_net_idx] : cut_bg_rect_net_pair_list) { + PlanarRect cut_rect = DRCUTIL.convertToPlanarRect(bg_env_rect); + if (DRCUTIL.exist(cut_rect_list, cut_rect)) { + continue; + } + cut_rect_list.push_back(cut_rect); + } + } + if (cut_rect_list.empty()) { + continue; + } + bool within_distance = false; + for (PlanarRect& cut_rect : cut_rect_list) { + if (DRCUTIL.getEuclideanDistance(routing_rect, cut_rect) < curr_rule.distance) { + within_distance = true; + break; + } + } + if (!within_distance) { + continue; + } + cut_cut_rect_list_list_map[cut_layer_idx].push_back(cut_rect_list); + } + } + } + if (!curr_rule.has_length) { + for (int32_t cut_layer_idx : check_cut_layer_idx_list) { + std::vector> cut_bg_rect_net_pair_list; + cut_bg_rtree_map[cut_layer_idx].query(bgi::intersects(DRCUTIL.convertToBGRectInt(routing_rect)), std::back_inserter(cut_bg_rect_net_pair_list)); + std::vector cut_rect_list; + for (auto& [bg_rect, cut_net_idx] : cut_bg_rect_net_pair_list) { + PlanarRect cut_rect = DRCUTIL.convertToPlanarRect(bg_rect); + if (!DRCUTIL.isClosedOverlap(cut_rect, routing_rect)) { + continue; + } + cut_rect_list.push_back(cut_rect); + } + cut_cut_rect_list_list_map[cut_layer_idx].push_back(cut_rect_list); + } + } + for (auto& [cut_layer_idx, cut_rect_list_list] : cut_cut_rect_list_list_map) { + for (std::vector& cut_rect_list : cut_rect_list_list) { + int32_t below_routing_layer_idx; + { + std::vector& routing_layer_idx_list = cut_to_adjacent_routing_map[cut_layer_idx]; + below_routing_layer_idx = *std::min_element(routing_layer_idx_list.begin(), routing_layer_idx_list.end()); + } + for (PlanarRect& cut_rect : cut_rect_list) { + Violation violation; + violation.set_violation_type(ViolationType::kMinimumCut); + violation.set_is_routing(true); + violation.set_violation_net_set({net_idx}); + violation.set_layer_idx(below_routing_layer_idx); + violation.set_rect(cut_rect); + violation.set_required_size(curr_rule.num_cuts); + rv_box.get_violation_list().push_back(violation); + } + } + } + } + } + } + } + } } } // namespace idrc diff --git a/src/operation/iDRC/source/toolkit/CMakeLists.txt b/src/operation/iDRC/source/toolkit/CMakeLists.txt index 411acd470cd1e4261ee0f87487896ad2f1b7d596..4a0c09b3e8130712169f3de7549190d71b3596ab 100644 --- a/src/operation/iDRC/source/toolkit/CMakeLists.txt +++ b/src/operation/iDRC/source/toolkit/CMakeLists.txt @@ -4,15 +4,15 @@ add_subdirectory(${IDRC_TOOLKIT}/utility) add_library(idrc_toolkit INTERFACE) -target_link_libraries(idrc_toolkit +target_link_libraries(idrc_toolkit INTERFACE - idrc_logger - idrc_monitor - idrc_utility - idrc_interface + idrc_logger + idrc_monitor + idrc_utility + idrc_interface ) -target_include_directories(idrc_toolkit +target_include_directories(idrc_toolkit INTERFACE - ${IDRC_TOOLKIT} + ${IDRC_TOOLKIT} ) diff --git a/src/operation/iDRC/source/toolkit/logger/CMakeLists.txt b/src/operation/iDRC/source/toolkit/logger/CMakeLists.txt index 800389be504788b04b4fd3c6180b1d36bb432175..408c623ac5d23e2d1446b1fac498bafb2180f911 100644 --- a/src/operation/iDRC/source/toolkit/logger/CMakeLists.txt +++ b/src/operation/iDRC/source/toolkit/logger/CMakeLists.txt @@ -1,8 +1,8 @@ -if(DEBUG_IDRC_LOGGER) - message(STATUS "DRC: DEBUG_IDRC_LOGGER") +if(DEBUG_IDRC_LOGGER) + message(STATUS "DRC: DEBUG_IDRC_LOGGER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "DRC: RELEASE_IDRC_LOGGER") + message(STATUS "DRC: RELEASE_IDRC_LOGGER") set(CMAKE_BUILD_TYPE "Release") endif() @@ -10,12 +10,12 @@ add_library(idrc_logger ${IDRC_TOOLKIT}/logger/Logger.cpp ) -target_link_libraries(idrc_logger +target_link_libraries(idrc_logger PUBLIC - idrc_data_manager + idrc_data_manager ) -target_include_directories(idrc_logger +target_include_directories(idrc_logger PUBLIC - ${IDRC_TOOLKIT}/logger + ${IDRC_TOOLKIT}/logger ) diff --git a/src/operation/iDRC/source/toolkit/monitor/CMakeLists.txt b/src/operation/iDRC/source/toolkit/monitor/CMakeLists.txt index d10199c805be7ae51b0cf150b82d495a25596bd0..87b695cf34a9125153c967c80965ff9e016b0bf5 100644 --- a/src/operation/iDRC/source/toolkit/monitor/CMakeLists.txt +++ b/src/operation/iDRC/source/toolkit/monitor/CMakeLists.txt @@ -1,8 +1,8 @@ -if(DEBUG_IDRC_MONITOR) - message(STATUS "DRC: DEBUG_IDRC_MONITOR") +if(DEBUG_IDRC_MONITOR) + message(STATUS "DRC: DEBUG_IDRC_MONITOR") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "DRC: RELEASE_IDRC_MONITOR") + message(STATUS "DRC: RELEASE_IDRC_MONITOR") set(CMAKE_BUILD_TYPE "Release") endif() @@ -10,12 +10,12 @@ add_library(idrc_monitor ${IDRC_TOOLKIT}/monitor/Monitor.cpp ) -target_link_libraries(idrc_monitor +target_link_libraries(idrc_monitor PUBLIC - idrc_data_manager + idrc_data_manager ) -target_include_directories(idrc_monitor +target_include_directories(idrc_monitor PUBLIC - ${IDRC_TOOLKIT}/monitor + ${IDRC_TOOLKIT}/monitor ) diff --git a/src/operation/iDRC/source/toolkit/utility/CMakeLists.txt b/src/operation/iDRC/source/toolkit/utility/CMakeLists.txt index f7667401125ba82647cdd4d7c54b4053c5b422a3..84ea7553dd348529297655ff8ad2d9f878029690 100644 --- a/src/operation/iDRC/source/toolkit/utility/CMakeLists.txt +++ b/src/operation/iDRC/source/toolkit/utility/CMakeLists.txt @@ -1,8 +1,8 @@ -if(DEBUG_IDRC_UTILITY) - message(STATUS "DRC: DEBUG_IDRC_UTILITY") +if(DEBUG_IDRC_UTILITY) + message(STATUS "DRC: DEBUG_IDRC_UTILITY") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "DRC: RELEASE_IDRC_UTILITY") + message(STATUS "DRC: RELEASE_IDRC_UTILITY") set(CMAKE_BUILD_TYPE "Release") endif() @@ -10,12 +10,12 @@ add_library(idrc_utility ${IDRC_TOOLKIT}/utility/Utility.cpp ) -target_link_libraries(idrc_utility +target_link_libraries(idrc_utility PUBLIC - idrc_data_manager + idrc_data_manager ) -target_include_directories(idrc_utility +target_include_directories(idrc_utility PUBLIC - ${IDRC_TOOLKIT}/utility + ${IDRC_TOOLKIT}/utility ) diff --git a/src/operation/iFP/README.md b/src/operation/iFP/README.md new file mode 100644 index 0000000000000000000000000000000000000000..11bfa00d44a91e9297dfb51127eb7132b4354938 --- /dev/null +++ b/src/operation/iFP/README.md @@ -0,0 +1,416 @@ +# iFP: Floorplanning + +## **FP_TCL Command User Manual** + +**Dependencies** + +- sudo apt-get install libunwind-dev +- sudo apt-get install libspdlog-dev (env : ubuntu20.04) +- sudo apt-get install boost 1.71 +- sudo apt-get install eigen + +**Build** + +git clone --recursive +cd iEDA +mkdir build +cd build +cmake.. +make + +**Run** + +cd iEDA/bin + +./FP gtest.tcl + +**Tool Update** + +cd iEDA + +git pull + +rm -rf build + +mkdir build + +cd build + +cmake.. + +make + +**#1. init_floorplan** + +- -die_area The area of the die, a string, with each value separated by spaces. The values here are not multiplied by DBU. +- -core_area The area of the core, a string, with each value separated by spaces. The values here are not multiplied by DBU. +- -core_site The selection of the core site. +- -io_site For the 110 process, this is an **optional parameter**, and "IOSite" will be selected by default. + +**## Example: ** + +set DIE_AREA "0.0 0.0 2843 2843" + +set CORE_AREA "150 150 2693 2693" + +set PLACE_SITE HD_CoreSite + +set IO_SITE IOSite + +init_floorplan \ + +​ -die_area $DIE_AREA \ + +​ -core_area $CORE_AREA \ + +​ -core_site $PLACE_SITE \ + +​ -io_site $IO_SITE + +**#2. placeInst** + +The tested functions include: + +1. Placing IOCells +2. Placing power CELLs +3. Placing IOFILLERs +4. Placing CORNERs + +When placing the above four types, placement checks will be performed. The rules are whether they are placed according to IOSite and whether they are on the DIE BOUNDARY. + + 5. Placing standard cells + +- -inst_name The name of the instance. +- -llx The abscissa of the lower left corner. The value at this time is the absolute coordinate, that is, the value after multiplying by DBU should be set. +- -lly The ordinate of the lower left corner. +- -orient Orientation, can use (N, S, W, E) or (R0, R180, R90, R270) +- -cellmaster The type of the cell. + +**## Example: ** + +placeInst \ + -inst_name u0_clk \ + -llx 0 \ + -lly 2510940 \ + -orient E \ + -cellmaster PX1W + +**#3. placePort** + +This command is only for generating ports of IOPINS connected to IOCells. Ports of power CELLs do not use this interface. + +- -pin_name The name of the iopin. +​- -offset_x The offset relative to the lower left corner coordinate of the connected IOCell. The absolute length should be set here, that is, the value after multiplying by DBU. +​- -offset_y The offset relative to the lower left corner coordinate of the connected IOCell. The absolute length should be set here, that is, the value after multiplying by DBU. +​- -width The width of the rectangle. The offset relative to the lower left corner coordinate of the connected IOCell. The absolute length should be set here, that is, the value after multiplying by DBU. +​- -height The height of the rectangle. The offset relative to the lower left corner coordinate of the connected IOCell. The absolute length should be set here, that is, the value after multiplying by DBU. +​- -layer The name of the layer it is on. + +**## Example: ** + +placePort \ + -pin_name osc_in_pad \ + -offset_x 9000 \ + -offset_y 71500 \ + -width 58000 \ + -height 58000 \ + -layer ALPA + +**#4. placeIoFiller** + +Place IOFILLERs, supporting automatic filling on four sides. + +Required parameter: -filler_types The type of IOFILLER. + +Optional parameters: + +- -prefix The prefix of the generated filler name. The default is IOFill. +- -edge Set which edge to fill. If not set, it is global filling. +- -begin_pos Set to fill within a certain line segment on a certain edge. If not set, the entire edge is filled by default. +- -end_pos The values of begin and pos here are doubles and are values before multiplying by DBU, similar to init. + +**## Example: ** + +placeIoFiller \ + -filler_types "PFILL50W PFILL20W PFILL10W PFILL5W PFILL2W PFILL01W PFILL001W" + +​ #-prefix + +​ #-edge + +​ #-begin_pos + +​ #-end_pos + +**#5. tapcell** + +Place tapcells and endcaps. + +- -tapcell Set the type of tapcell. +- -distance 32.5 Set the distance of tapcells. The value here is not multiplied by DBU. +- -endcap The type of endcap. + +**## Example: ** + +tapcell \ + -tapcell LVT_FILLTIEHD \ + -distance 32.5 \ + -endcap LVT_F_FILLHD1 + +**#6. global_net_connect** + +Create power nets. + +- -net_name The name of the power network. +- -instance_pin_name The name of the pin of the instance connected to this network. Currently, it does not support specifying that the pins of certain instances are connected to this power network. By default, all instances with this pin globally are connected to this network. +- -is_power Should be set to 1 or 0: 1 represents use power, 0 represents use ground. + +**## Example: ** + +global_net_connect \ + -net_name VDD \ + -instance_pin_name VDD \ + -is_power 1 + +global_net_connect \ + -net_name VDD \ + -instance_pin_name VDDIO \ + -is_power 1 + +global_net_connect \ + -net_name VSS \ + -instance_pin_name VSS \ + -is_power 0 + +**#7. add_pdn_io** + +Add IOPINS for the power NET. + +- -net_name The name of the power network. +- -direction Parameter (INPUT, OUTPUT, INOUT, FEEDTHRU, OUTTRI), the data direction of the pin. +- -pin_name Optional parameter. The default is the name of the power network. + +**## Example: ** + +add_pdn_io \ + -net_name VDD \ + -direction INOUT + +​ #-pin_name VDD + +**#8. place_pdn_Port** + +Add PORTs for the IOPINS of the power network. + +- -pin_name The name of the iopin. +- -io_cell_name The name of the io io cell. +- -offset_x Offset relative to the lower left corner of the port rectangle of the io cell. +- -offset_y Offset relative to the lower left corner of the port rectangle of the io cell. +- -width The width of the rectangle. +- -height The height of the rectangle. +- -layer The routing layer to which the port belongs. + +**## Example: ** + +place_pdn_Port \ + -pin_name VDD \ + -io_cell_name xxx\ + -offset_x 10 \ + -offset_y 10 \ + -width 100 \ + -height 100 \ + -layer ALPA + +place_pdn_Port \ + -pin_name VDD \ + -io_cell_name xxx\ + -offset_x 20 \ + -offset_y 20 \ + -width 200 \ + -height 200 \ + -layer ALPA These two commands can add two ports for the VDD pin. + + + +**#9. create_grid** + +Generate power supply lines for standard cells and generate routing information. + +- -layer_name The layer on which the power grid is generated. +- -net_name_power The name of the power net. +- -net_name_ground The name of the ground net. +- -width The line width. The value is not multiplied by DBU. +- -offset The offset relative to the core boundary. It is recommended to set it to 0. Only the case where the offset is 0 has been tested. The value is not multiplied by DBU. + +**## Example: ** + +create_grid \ + -layer_name "METAL1" \ + -net_name_power VDD \ + -net_name_ground VSS \ + -width 0.24 \ + -offset 0 + +**#10. create_stripe** + +Generate bar-shaped power supply lines for standard cells. + +- -layer_name The layer on which the power supply line is generated. +- -net_name_power The name of the power net. +- -net_name_ground The name of the ground net. +- -width The line width. The value is not multiplied by DBU. +- -pitch The pitch of the same type of power supply lines. For standard cells, the pitch between the power line and the ground line of the same layer is 0.5*pitch. +- -offset The offset relative to the core boundary. The value is not multiplied by DBU. + +**## Example: ** + +create_stripe \ + -layer_name "METAL5" \ + -net_name_power VDD \ + -net_name_ground VSS \ + -width 1.64 \ + -pitch 13.12 \ + -offset 3.895 + +**#11. connect_two_layer** + +Connect the specified two layers of power supply lines. + +- -layers : Can be input one pair at a time or all the layer information that needs to be connected can be input together. + +**## Example: ** + +set connect1 "METAL1 METAL4" \ +set connect2 "METAL4 METAL5" \ +set connect3 "METAL5 METAL6" \ +set connect4 "METAL6 METAL7" \ +set connect5 "METAL7 METAL8" \ +set connect6 "METAL8 ALPA" \ +connect_two_layer \ + -layers [concat \$connect1 ​\$connect2 ​\$connect3 ​\$connect4 ​\$connect5 $connect6] + +1. connect_two_layer \ + -layers [concat \$connect1 $connect2] +2. connect_two_layer \ + -layers "METAL1 METAL4" + connect_two_layer \ + -layers "METAL4 METAL5" **The effects of sequence 1 and 2 are the same** + +**PS: The two layers to be connected need to contain power supply lines** + +**#12. connect_io_pin_to_pdn** + +Connect the Port of the IOPIN of the power NET to the power supply line in the Core. (The coordinates of the Port will be checked) +- -point_list The coordinate points of the corners passed by the connection relationship (the coordinates of the starting point and the ending point also need to be included), or only the starting and ending coordinates can be input. +- -layer The layer on which you want to perform the connection. + +**## Example: ** +connect_io_pin_to_pdn \ + -point_list "998 2802 915 2598" \ + -layer METAL1 + +**#13. connect_pdn_stripe** +- -point_list The coordinate points of the corners passed by the connection relationship (the starting point and the ending point coordinates also need to be included) +- -net_name The name of the power network you want to connect to +- -layer The layer on which you want to perform the connection +**## Example: ** +connect_pdn_stripe \ + -point_list "2675.606 1998.707 2680.606 1998.707 2680.606 1892.165 2803.686 1892.165" \ + -net_name VDD \ + -layer ALPA + +connect_pdn_stripe \ + -point_list "2675.606 1998.707 2680.606 1998.707" \ + -net_name VDD \ + -layer ALPA \ + -width 100 +connect_pdn_stripe \ + -point_list "2680.606 1892.165 2803.686 1892.165" \ + -net_name VDD \ + -layer ALPA \ + -width 100 + +**#14. add_segment_via** +Add vias to the power supply line. + +- -net_name The name of the power supply line. +- -layer The layer where the via is located. +- -top_layer The top layer of the metal layer. +- -bottom_layer The bottom layer of the metal layer. +​- -offset_x The offset relative to the lower left corner coordinate of the connected IOCell. The absolute length should be set here, that is, the value after multiplying by DBU. +​- -offset_y The offset relative to the lower left corner coordinate of the connected IOCell. The absolute length should be set here, that is, the value after multiplying by DBU. +​- -width The width of the rectangle. The offset relative to the lower left corner coordinate of the connected IOCell. The absolute length should be set here, that is, the value after multiplying by DBU. +​- -height The height of the rectangle. The offset relative to the lower left corner coordinate of the connected IOCell. The absolute length should be set here, that is, the value after multiplying by DBU. + +**## Example: ** + +add_segment_via \ + -net_name VDD \ + -layer VIA45 \ + -offset_x 9000 \ + -offset_y 71500 \ + -width 58000 \ + -height 58000 + +add_segment_via \ + -net_name VDD \ + -layer VIA45 \ + -offset_x 10000 \ + -offset_y 81500 \ + -width 58000 \ + -height 58000 + +add_segment_via \ + -net_name VDD \ + -top_layer METAL8 \ + -bottom_layer METAL1 \ + -offset_x 10000 \ + -offset_y 81500 \ + -width 58000 \ + -height 58000 + +add_segment_via \ + -net_name VDDIO \ + -top_layer METAL8 \ + -bottom_layer METAL1 \ + -offset_x 10000 \ + -offset_y 81500 \ + -width 58000 \ + -height 58000 + +**#15. add_segment_stripe** +- -point_list The connection points for generating the stripe. When the number of connection points is greater than 2, the front and back connection points generate stripes pairwise. +- -net_name The name of the power network you want to connect to. +- -layer The layer on which you want to perform the connection. +- -width Specify the line width. +add_segment_stripe \ + -point_list "2680.606 1892.165 2803.686 1892.165" \ + -net_name VDDIO \ + -layer ALPA \ + -width 100 + +add_segment_stripe \ + -point_list "1680.606 2892.165 2803.686 2892.165 2803.686 1792.165" \ + -net_name VDDIO \ + -layer ALPA \ + -width 100 + +add_segment_stripe \ + -point_begin "3680.606 2892.165" \ + -layer_start METAL4 \ + -point_end "4680.606 2892.165" \ + -layer_end METAL8 \ + -net_name VDDIO \ + -via_width 100 \ + -via_height 200 + + + + +**#16. read_lef** + +Read the lef file in the form of a string list. + +**## Example: ** + +read_lef "../../Designs/scc011u_8lm_1tm_thin_ALPA/scc011u_8lm_1tm_th \ No newline at end of file diff --git a/src/operation/iFP/api/ifp_api.cpp b/src/operation/iFP/api/ifp_api.cpp index 08a48b3b866bf5bab6a8f6dd9e4303e9e829b941..8f6727e7b0c1d22219021c669607a13425efeb59 100644 --- a/src/operation/iFP/api/ifp_api.cpp +++ b/src/operation/iFP/api/ifp_api.cpp @@ -85,11 +85,11 @@ bool FpApi::makeTracks(std::string layer_name, int x_offset, int x_pitch, int y_ * @return true * @return false */ -bool FpApi::autoPlacePins(std::string layer_name, int width, int height) +bool FpApi::autoPlacePins(std::string layer_name, int width, int height, std::vector sides) { IoPlacer io_placer; - return io_placer.autoPlacePins(layer_name, width, height); + return io_placer.autoPlacePins(layer_name, width, height, sides); } bool FpApi::placePort(std::string pin_name, int32_t x_offset, int32_t y_offset, int32_t rect_width, int32_t rect_height, diff --git a/src/operation/iFP/api/ifp_api.h b/src/operation/iFP/api/ifp_api.h index e28d0b988ba3f73a9b58af4e9c1aed3b6108850e..5cf1b60414f56b243b5197a0376683a14aa30635 100644 --- a/src/operation/iFP/api/ifp_api.h +++ b/src/operation/iFP/api/ifp_api.h @@ -48,7 +48,7 @@ class FpApi bool initCore(double core_lx, double core_ly, double core_ux, double core_uy, std::string core_site_name, std::string iocell_site_name, std::string corner_site_name); bool makeTracks(std::string layer_name, int x_offset, int x_pitch, int y_offset, int y_pitch); - bool autoPlacePins(std::string layer_name, int width, int height); + bool autoPlacePins(std::string layer_name, int width, int height, std::vector sides); bool placePort(std::string pin_name, int32_t x_offset, int32_t y_offset, int32_t rect_width, int32_t rect_height, std::string layer_name); bool autoPlacePad(std::vector pad_masters, std::vector conner_masters); bool placeIOFiller(std::vector filler_name_list, std::string prefix); diff --git a/src/operation/iFP/source/module/io_placer/io_placer.cpp b/src/operation/iFP/source/module/io_placer/io_placer.cpp index fb1fc8c9548904509fe0a12a39da726e9ee4d631..a7577c2ca3c86e587815bc32a7f47bbbaba22044 100644 --- a/src/operation/iFP/source/module/io_placer/io_placer.cpp +++ b/src/operation/iFP/source/module/io_placer/io_placer.cpp @@ -77,11 +77,21 @@ bool IoPlacer::edgeIsSameToOrient(Edge edge, idb::IdbOrient orient) * @param layer_name * @param width * @param height + * @param sides : place io pin in sides, options : left, right, top, bottom * @return true * @return false */ -bool IoPlacer::autoPlacePins(std::string layer_name, int width, int height) +bool IoPlacer::autoPlacePins(std::string layer_name, int width, int height, std::vector sides) { + auto has_side = [&](std::string side) -> bool { + auto it = std::find(sides.begin(), sides.end(), side); + if (it != sides.end()) { + return true; + } else { + return sides.size() == 0 ? true : false; + } + }; + auto idb_design = dmInst->get_idb_design(); auto idb_layout = idb_design->get_layout(); @@ -92,7 +102,8 @@ bool IoPlacer::autoPlacePins(std::string layer_name, int width, int height) /// calculate all the location int pin_num = pin_list.size(); - int edge_num = pin_num % 4 == 0 ? pin_num / 4 : pin_num / 4 + 1; + int side_num = sides.size() > 0 ? sides.size() : 4; + int edge_num = pin_num % side_num == 0 ? pin_num / side_num : pin_num / side_num + 1; int manufacture_grid = dmInst->get_idb_lef_service()->get_layout()->get_munufacture_grid(); int width_step = idb_core->get_bounding_box()->get_width() / (edge_num + 1); int height_step = idb_core->get_bounding_box()->get_height() / (edge_num + 1); @@ -100,123 +111,155 @@ bool IoPlacer::autoPlacePins(std::string layer_name, int width, int height) height_step = height_step / manufacture_grid * manufacture_grid; int pin_index = 0; /// left - for (int i = 0; i < edge_num; ++i) { - if (pin_index >= pin_num) { - break; - } + if (has_side("left")) { + for (int i = 0; i < edge_num; ++i) { + if (pin_index >= pin_num) { + break; + } - int x = idb_die->get_llx() + width / 2; - int y = idb_core->get_bounding_box()->get_low_y() + i * height_step; - - auto pin = pin_list[pin_index++]; - pin->set_location(x, y); - - auto io_term = pin->get_term(); - io_term->set_placement_status_place(); - auto port = io_term->add_port(nullptr); - auto shape = port->add_layer_shape(); - shape->set_type_rect(); - - // Calculate shape coordinates with left-bottom corner aligned to manufacture_grid - int shape_llx = x - width / 2; - int shape_lly = y - height / 2; - shape_llx = (shape_llx / manufacture_grid) * manufacture_grid; - shape_lly = (shape_lly / manufacture_grid) * manufacture_grid; - int shape_urx = shape_llx + width; - int shape_ury = shape_lly + height; - - shape->add_rect(shape_llx - x, shape_lly - y, shape_urx - x, shape_ury - y); - shape->set_layer(layer); + int x = idb_die->get_llx() + width / 2; + int y = idb_core->get_bounding_box()->get_low_y() + i * height_step; + + auto pin = pin_list[pin_index++]; + + auto io_term = pin->get_term(); + io_term->set_placement_status_place(); + auto port = io_term->add_port(nullptr); + if (pin->get_term()->is_port_exist() || pin->is_special_net_pin()) { + port->set_placement_status_place(); + port->set_coordinate(x, y); + } else { + pin->set_location(x, y); + } + auto shape = port->add_layer_shape(); + shape->set_type_rect(); + + // Calculate shape coordinates with left-bottom corner aligned to manufacture_grid + int shape_llx = x - width / 2; + int shape_lly = y - height / 2; + shape_llx = (shape_llx / manufacture_grid) * manufacture_grid; + shape_lly = (shape_lly / manufacture_grid) * manufacture_grid; + int shape_urx = shape_llx + width; + int shape_ury = shape_lly + height; + + shape->add_rect(shape_llx - x, shape_lly - y, shape_urx - x, shape_ury - y); + shape->set_layer(layer); + } } /// right - for (int i = 0; i < edge_num; ++i) { - if (pin_index >= pin_num) { - break; - } + if (has_side("right")) { + for (int i = 0; i < edge_num; ++i) { + if (pin_index >= pin_num) { + break; + } + + int x = idb_die->get_urx() - width / 2; + int y = idb_core->get_bounding_box()->get_low_y() + i * height_step; - int x = idb_die->get_urx() - width / 2; - int y = idb_core->get_bounding_box()->get_low_y() + i * height_step; - - auto pin = pin_list[pin_index++]; - pin->set_location(x, y); - - auto io_term = pin->get_term(); - io_term->set_placement_status_place(); - auto port = io_term->add_port(nullptr); - auto shape = port->add_layer_shape(); - shape->set_type_rect(); - - // Calculate shape coordinates with left-bottom corner aligned to manufacture_grid - int shape_llx = x - width / 2; - int shape_lly = y - height / 2; - shape_llx = (shape_llx / manufacture_grid) * manufacture_grid; - shape_lly = (shape_lly / manufacture_grid) * manufacture_grid; - int shape_urx = shape_llx + width; - int shape_ury = shape_lly + height; - - shape->add_rect(shape_llx - x, shape_lly - y, shape_urx - x, shape_ury - y); - shape->set_layer(layer); + auto pin = pin_list[pin_index++]; + + auto io_term = pin->get_term(); + io_term->set_placement_status_place(); + auto port = io_term->add_port(nullptr); + if (pin->get_term()->is_port_exist() || pin->is_special_net_pin()) { + port->set_placement_status_place(); + port->set_coordinate(x, y); + } else { + pin->set_location(x, y); + } + + auto shape = port->add_layer_shape(); + shape->set_type_rect(); + + // Calculate shape coordinates with left-bottom corner aligned to manufacture_grid + int shape_llx = x - width / 2; + int shape_lly = y - height / 2; + shape_llx = (shape_llx / manufacture_grid) * manufacture_grid; + shape_lly = (shape_lly / manufacture_grid) * manufacture_grid; + int shape_urx = shape_llx + width; + int shape_ury = shape_lly + height; + + shape->add_rect(shape_llx - x, shape_lly - y, shape_urx - x, shape_ury - y); + shape->set_layer(layer); + } } /// bottom - for (int i = 0; i < edge_num; ++i) { - if (pin_index >= pin_num) { - break; - } + if (has_side("bottom")) { + for (int i = 0; i < edge_num; ++i) { + if (pin_index >= pin_num) { + break; + } + + int x = idb_core->get_bounding_box()->get_low_x() + i * width_step; + int y = idb_die->get_lly() + height / 2; - int x = idb_core->get_bounding_box()->get_low_x() + i * width_step; - int y = idb_die->get_lly() + height / 2; - - auto pin = pin_list[pin_index++]; - pin->set_location(x, y); - - auto io_term = pin->get_term(); - io_term->set_placement_status_place(); - auto port = io_term->add_port(nullptr); - auto shape = port->add_layer_shape(); - shape->set_type_rect(); - - // Calculate shape coordinates with left-bottom corner aligned to manufacture_grid - int shape_llx = x - width / 2; - int shape_lly = y - height / 2; - shape_llx = (shape_llx / manufacture_grid) * manufacture_grid; - shape_lly = (shape_lly / manufacture_grid) * manufacture_grid; - int shape_urx = shape_llx + width; - int shape_ury = shape_lly + height; - - shape->add_rect(shape_llx - x, shape_lly - y, shape_urx - x, shape_ury - y); - shape->set_layer(layer); + auto pin = pin_list[pin_index++]; + + auto io_term = pin->get_term(); + io_term->set_placement_status_place(); + auto port = io_term->add_port(nullptr); + if (pin->get_term()->is_port_exist() || pin->is_special_net_pin()) { + port->set_placement_status_place(); + port->set_coordinate(x, y); + } else { + pin->set_location(x, y); + } + + auto shape = port->add_layer_shape(); + shape->set_type_rect(); + + // Calculate shape coordinates with left-bottom corner aligned to manufacture_grid + int shape_llx = x - width / 2; + int shape_lly = y - height / 2; + shape_llx = (shape_llx / manufacture_grid) * manufacture_grid; + shape_lly = (shape_lly / manufacture_grid) * manufacture_grid; + int shape_urx = shape_llx + width; + int shape_ury = shape_lly + height; + + shape->add_rect(shape_llx - x, shape_lly - y, shape_urx - x, shape_ury - y); + shape->set_layer(layer); + } } /// top - for (int i = 0; i < edge_num; ++i) { - if (pin_index >= pin_num) { - break; - } + if (has_side("top")) { + for (int i = 0; i < edge_num; ++i) { + if (pin_index >= pin_num) { + break; + } + + int x = idb_core->get_bounding_box()->get_low_x() + i * width_step; + int y = idb_die->get_ury() - height / 2; - int x = idb_core->get_bounding_box()->get_low_x() + i * width_step; - int y = idb_die->get_ury() - height / 2; - - auto pin = pin_list[pin_index++]; - pin->set_location(x, y); - - auto io_term = pin->get_term(); - io_term->set_placement_status_place(); - auto port = io_term->add_port(nullptr); - auto shape = port->add_layer_shape(); - shape->set_type_rect(); - - // Calculate shape coordinates with left-bottom corner aligned to manufacture_grid - int shape_llx = x - width / 2; - int shape_lly = y - height / 2; - shape_llx = (shape_llx / manufacture_grid) * manufacture_grid; - shape_lly = (shape_lly / manufacture_grid) * manufacture_grid; - int shape_urx = shape_llx + width; - int shape_ury = shape_lly + height; - - shape->add_rect(shape_llx - x, shape_lly - y, shape_urx - x, shape_ury - y); - shape->set_layer(layer); + auto pin = pin_list[pin_index++]; + + auto io_term = pin->get_term(); + io_term->set_placement_status_place(); + + auto port = io_term->add_port(nullptr); + if (pin->get_term()->is_port_exist() || pin->is_special_net_pin()) { + port->set_placement_status_place(); + port->set_coordinate(x, y); + } else { + pin->set_location(x, y); + } + + auto shape = port->add_layer_shape(); + shape->set_type_rect(); + + // Calculate shape coordinates with left-bottom corner aligned to manufacture_grid + int shape_llx = x - width / 2; + int shape_lly = y - height / 2; + shape_llx = (shape_llx / manufacture_grid) * manufacture_grid; + shape_lly = (shape_lly / manufacture_grid) * manufacture_grid; + int shape_urx = shape_llx + width; + int shape_ury = shape_lly + height; + + shape->add_rect(shape_llx - x, shape_lly - y, shape_urx - x, shape_ury - y); + shape->set_layer(layer); + } } return true; diff --git a/src/operation/iFP/source/module/io_placer/io_placer.h b/src/operation/iFP/source/module/io_placer/io_placer.h index 9909b18edd739396f7a9773f308ce9959995dbb8..72d7852a5f32710ce3da2f135da27c42b22e18b4 100644 --- a/src/operation/iFP/source/module/io_placer/io_placer.h +++ b/src/operation/iFP/source/module/io_placer/io_placer.h @@ -43,7 +43,7 @@ class IoPlacer ~IoPlacer() {} /// operator - bool autoPlacePins(std::string layer_name, int width, int height); + bool autoPlacePins(std::string layer_name, int width, int height, std::vector sides); bool placePort(std::string pin_name, int32_t x_offset, int32_t y_offset, int32_t rect_width, int32_t rect_height, std::string layer_name); bool autoPlacePad(std::vector pad_masters = {}, std::vector conner_masters = {}); @@ -55,7 +55,7 @@ class IoPlacer void set_pad_coords(vector conner_masters = {}); void placeIOFiller(std::vector& fillers, const std::string prefix, PadCoordinate coord); - void fillInterval(Interval interval, std::vector fillers, const std::string prefix, PadCoordinate coord); + void fillInterval(Interval interval, std::vector fillers, const std::string prefix, PadCoordinate coord); int32_t transUnitDB(double value); idb::IdbOrient transferEdgeToOrient(Edge edge); diff --git a/src/operation/iFP/source/module/tap_cell/tapcell.cpp b/src/operation/iFP/source/module/tap_cell/tapcell.cpp index 49af3cb51706cf06ed1ededee85845180b71bbeb..ff10cfbc1c51a476ad01276bfe4fbb219009fffa 100644 --- a/src/operation/iFP/source/module/tap_cell/tapcell.cpp +++ b/src/operation/iFP/source/module/tap_cell/tapcell.cpp @@ -85,6 +85,9 @@ int TapCellPlacer::buildTapcellRegion() auto row_list = idb_rows->get_row_list(); for (size_t i = 0; i < row_list.size(); i++) { buildRegionInRow(row_list[i], i); + auto y = row_list[i]->get_original_coordinate()->get_y(); + _top_y = std::max(_top_y, y); + _bottom_y = std::min(_bottom_y, y); } return _cell_region_list.size(); @@ -198,66 +201,76 @@ int TapCellPlacer::insertCell(int32_t inst_space, std::string tapcell_name, std: /// get width for endcap by orient int32_t endcap_width = getCellMasterWidthByOrient(endcap_master, region.orient); - /// insert endcap at the begin - if ((region.end - region.start) >= endcap_width) { - dmInst->createInstance("ENDCAP_" + std::to_string(endcap_index++), endcap_name, region.start, region.y, region.orient, - idb::IdbInstanceType::kDist, idb::IdbPlacementStatus::kFixed); - } - /// insert endcap at the end - if ((region.end - region.start) >= (2 * endcap_width)) { - dmInst->createInstance("ENDCAP_" + std::to_string(endcap_index++), endcap_name, region.end - endcap_width, region.y, region.orient, - idb::IdbInstanceType::kDist, idb::IdbPlacementStatus::kFixed); - } - - /// insert tapcell in the middle region - { - /// get core low bottom x - int32_t core_start_x = idb_core->get_bounding_box()->get_low_x(); - - /// get start & end of this region plus endcap width - int32_t region_start = region.start + endcap_width; - int32_t region_end = region.end - endcap_width; - - /// get width for tapcell and endcap by orient - int32_t tapcell_width = getCellMasterWidthByOrient(tapcell_master, region.orient); - int32_t coord_x = region_start; - while ((coord_x + tapcell_width) <= region_end) { - /// process first tapcell - if (coord_x == region_start) { - /// insert tapcell - if (region.index % 2 == 0) { - dmInst->createInstance("PHY_" + std::to_string(tapcell_index++), tapcell_name, region_start, region.y, region.orient, - idb::IdbInstanceType::kDist, idb::IdbPlacementStatus::kFixed); - /// 以core x为基准,inst_space为间距,奇偶行交错对齐tapcell - /// 校准偶数行起始点x - coord_x = core_start_x + ((coord_x - core_start_x) / inst_space + 2) * inst_space; - } else { - /// 校准奇数行起始点x - coord_x = core_start_x + ((coord_x - core_start_x) / inst_space + 1) * inst_space; - } - - continue; - } + /// process top and bottom endcap + if (region.y == _top_y || region.y == _bottom_y) { + for (auto x = region.start; x < region.end; x += endcap_width) { + dmInst->createInstance("ENDCAP_" + std::to_string(endcap_index++), endcap_name, x, region.y, region.orient, + idb::IdbInstanceType::kDist, idb::IdbPlacementStatus::kFixed); + } + } else { + /// process area between top and bottom row - /// process middle cell - dmInst->createInstance("PHY_" + std::to_string(tapcell_index++), tapcell_name, coord_x, region.y, region.orient, + /// insert endcap at the begin + if ((region.end - region.start) >= endcap_width) { + dmInst->createInstance("ENDCAP_" + std::to_string(endcap_index++), endcap_name, region.start, region.y, region.orient, idb::IdbInstanceType::kDist, idb::IdbPlacementStatus::kFixed); + } + /// insert endcap at the end + if ((region.end - region.start) >= (2 * endcap_width)) { + dmInst->createInstance("ENDCAP_" + std::to_string(endcap_index++), endcap_name, region.end - endcap_width, region.y, region.orient, + idb::IdbInstanceType::kDist, idb::IdbPlacementStatus::kFixed); + } - /// process last tapcell - if ((coord_x + 2 * inst_space) >= region_end) { - /// add tapcell to the end of the row adjacentd to the endcap - /// at less 2 tapcell width is needed in order to insert tapcell - if ((region_end - coord_x) > (tapcell_width * 2)) { - /// insert tapcell at the end, - /// and coordinate x = region_end - tapcell_width + /// insert tapcell in the middle region + { + /// get core low bottom x + int32_t core_start_x = idb_core->get_bounding_box()->get_low_x(); + + /// get start & end of this region plus endcap width + int32_t region_start = region.start + endcap_width; + int32_t region_end = region.end - endcap_width; + + /// get width for tapcell and endcap by orient + int32_t tapcell_width = getCellMasterWidthByOrient(tapcell_master, region.orient); + int32_t coord_x = region_start; + while ((coord_x + tapcell_width) <= region_end) { + /// process first tapcell + if (coord_x == region_start) { + /// insert tapcell if (region.index % 2 == 0) { - dmInst->createInstance("PHY_" + std::to_string(tapcell_index++), tapcell_name, region_end - tapcell_width, region.y, - region.orient, idb::IdbInstanceType::kDist, idb::IdbPlacementStatus::kFixed); + dmInst->createInstance("PHY_" + std::to_string(tapcell_index++), tapcell_name, region_start, region.y, region.orient, + idb::IdbInstanceType::kDist, idb::IdbPlacementStatus::kFixed); + /// 以core x为基准,inst_space为间距,奇偶行交错对齐tapcell + /// 校准偶数行起始点x + coord_x = core_start_x + ((coord_x - core_start_x) / inst_space + 2) * inst_space; + } else { + /// 校准奇数行起始点x + coord_x = core_start_x + ((coord_x - core_start_x) / inst_space + 1) * inst_space; } + + continue; } - } - coord_x += (inst_space * 2); + /// process middle cell + dmInst->createInstance("PHY_" + std::to_string(tapcell_index++), tapcell_name, coord_x, region.y, region.orient, + idb::IdbInstanceType::kDist, idb::IdbPlacementStatus::kFixed); + + /// process last tapcell + if ((coord_x + 2 * inst_space) >= region_end) { + /// add tapcell to the end of the row adjacentd to the endcap + /// at less 2 tapcell width is needed in order to insert tapcell + if ((region_end - coord_x) > (tapcell_width * 2)) { + /// insert tapcell at the end, + /// and coordinate x = region_end - tapcell_width + if (region.index % 2 == 0) { + dmInst->createInstance("PHY_" + std::to_string(tapcell_index++), tapcell_name, region_end - tapcell_width, region.y, + region.orient, idb::IdbInstanceType::kDist, idb::IdbPlacementStatus::kFixed); + } + } + } + + coord_x += (inst_space * 2); + } } } } diff --git a/src/operation/iFP/source/module/tap_cell/tapcell.h b/src/operation/iFP/source/module/tap_cell/tapcell.h index 7bc6f8f8aad03d0d3ef238de88c96fb3f13564f9..1f2d7974ca99caf590a8c70e85e3b1fe72ede811 100644 --- a/src/operation/iFP/source/module/tap_cell/tapcell.h +++ b/src/operation/iFP/source/module/tap_cell/tapcell.h @@ -17,6 +17,8 @@ #pragma once #include +#include + #include #include #include @@ -50,6 +52,8 @@ class TapCellPlacer private: std::vector _cell_region_list; + int _top_y = INT_MIN; + int _bottom_y = INT_MAX; bool checkDistance(int32_t distance); int buildTapcellRegion(); diff --git a/src/operation/iIR/README.md b/src/operation/iIR/README.md index 399c77d4a4557174628ccb6621d7fa7369934ff7..181249eb13cdec161f3685108ee2aec3ac47b1b1 100644 --- a/src/operation/iIR/README.md +++ b/src/operation/iIR/README.md @@ -1,4 +1,4 @@ -# User guide of iIR +# iIR: IR Drop Calculation ## Introduction to the iIR The iIR tool is mainly used for analyzing the IR drop of the power distribution network. diff --git a/src/operation/iIR/api/iIR.hh b/src/operation/iIR/api/iIR.hh index 9307357bb24125bce44565f534dc1173acf9a001..be91336a375d9eb8f1df2f3a8cea18691c520b0b 100644 --- a/src/operation/iIR/api/iIR.hh +++ b/src/operation/iIR/api/iIR.hh @@ -34,7 +34,7 @@ namespace iir { /** * @brief The instance power data. * - * + * */ struct IRInstancePower { const char* _instance_name; @@ -47,7 +47,7 @@ struct IRInstancePower { /** * @brief The ir solver method enum. - * + * */ enum class IRSolverMethod { kLUSolver, // LU solver @@ -58,14 +58,16 @@ using IRNodeLoc = std::pair, std::string>; /** * @brief The IR top interface. - * + * */ class iIR { public: void set_rc_data(const void* rust_rc_data) { _rc_data = rust_rc_data; } auto* get_rc_data() { return _rc_data; } - void set_nominal_voltage(double nominal_voltage) { _nominal_voltage = nominal_voltage; } + void set_nominal_voltage(double nominal_voltage) { + _nominal_voltage = nominal_voltage; + } double get_nominal_voltage() { return _nominal_voltage; } auto& get_net_to_instance_ir_drop() { return _net_to_instance_ir_drop; } @@ -73,16 +75,15 @@ class iIR { unsigned init(); unsigned readSpef(std::string_view spef_file_path); unsigned readInstancePowerDB(std::string_view instance_power_file_path); - unsigned setInstancePowerData(std::vector instance_power_data); + unsigned setInstancePowerData( + std::vector instance_power_data); void set_net_bump_node_locs( const std::map& net_bump_node_locs) { - _net_bump_node_locs = net_bump_node_locs; + _net_bump_node_locs = net_bump_node_locs; } - auto& get_net_bump_node_locs() const { - return _net_bump_node_locs; - } + auto& get_net_bump_node_locs() const { return _net_bump_node_locs; } unsigned solveIRDrop(const char* net_name); @@ -94,8 +95,10 @@ class iIR { std::map> _net_to_instance_ir_drop; - std::map _net_bump_node_locs; //!< The net bump node locs. + std::map + _net_bump_node_locs; //!< The net bump node locs. - IRSolverMethod _solver_method = IRSolverMethod::kLUSolver; //!< The IR solver method. + IRSolverMethod _solver_method = + IRSolverMethod::kCGSolver; //!< The IR solver method. }; } // namespace iir \ No newline at end of file diff --git a/src/operation/iIR/source/ir-solver/IRSolver.cc b/src/operation/iIR/source/ir-solver/IRSolver.cc index 0883a945b6e49567ab1cb1c71cc407914e2ed0a5..5b79f9fdc6721327cb9a0bdb42ed204412b6886e 100644 --- a/src/operation/iIR/source/ir-solver/IRSolver.cc +++ b/src/operation/iIR/source/ir-solver/IRSolver.cc @@ -25,15 +25,16 @@ * */ -#include -#include +#include "IRSolver.hh" + #include +#include +#include #include #include #include -#include "IRSolver.hh" #include "log/Log.hh" #if CUDA_IR_SOLVER #include "ir-solver-cuda/ir_solver.cuh" @@ -49,10 +50,10 @@ namespace iir { */ void PrintMatrix(Eigen::Map>& G_matrix, Eigen::Index base_index, Eigen::Index num_nodes) { - LOG_INFO << "start write matrix, num nodes: " << num_nodes << ", base index: " << base_index; - std::ofstream out("/home/taosimin/iEDA24/iEDA/bin/matrix_m9_m7.txt", std::ios::trunc); + std::ofstream out("/home/taosimin/iEDA24/iEDA/bin/matrix_m9_m7.txt", + std::ios::trunc); for (Eigen::Index i = base_index; i < base_index + num_nodes; ++i) { for (Eigen::Index j = base_index; j < base_index + num_nodes; ++j) { // LOG_INFO << "matrix element at (" << i << ", " << j @@ -102,7 +103,6 @@ void PrintCSCMatrix(Eigen::Map>& G_matrix) { * @param v_vector */ void PrintVector(const Eigen::VectorXd& v_vector, const std::string& filename) { - std::ofstream out(filename, std::ios::trunc); for (Eigen::Index i = 0; i < v_vector.size(); ++i) { // LOG_INFO << "vector element at (" << i << "): " << v_vector(i); @@ -160,8 +160,8 @@ std::vector IRSolver::getIRDrop(Eigen::VectorXd& v_vector) { std::vector IRLUSolver::operator()( Eigen::Map>& G_matrix, Eigen::VectorXd& J_vector) { - - Eigen::SparseMatrix A = G_matrix; // Copy G_matrix to A for preconditioning + Eigen::SparseMatrix A = + G_matrix; // Copy G_matrix to A for preconditioning // PrintMatrix(G_matrix, 0, G_matrix.rows()); @@ -234,14 +234,14 @@ Eigen::VectorXd conjugateGradient(const Eigen::SparseMatrix& A, int min_residual_iter = 0; for (; i < max_iter; ++i) { LOG_INFO_EVERY_N(1000) << "CG iteration num: " << i + 1 - << " residual: " << sqrt(rsold); + << " residual: " << sqrt(rsold); // LOG_INFO_EVERY_N(200) << "x:\n"<< x.transpose(); // L2 regularization for gradient Eigen::VectorXd Ap = A * p + lambda * p; // PrintVector(Ap, "/home/taosimin/iEDA24/iEDA/bin/Ap.txt"); - double pAp = p.dot(Ap); + double pAp = p.dot(Ap); double alpha = rsold / pAp; // PrintVector(p, "/home/taosimin/iEDA24/iEDA/bin/p.txt"); @@ -276,7 +276,7 @@ Eigen::VectorXd conjugateGradient(const Eigen::SparseMatrix& A, // LOG_INFO << "current residual: " << sqrt(rsnew); if (sqrt(rsnew) < tol) { - rsold = rsnew; + rsold = rsnew; ++i; break; } @@ -308,58 +308,57 @@ Eigen::VectorXd conjugateGradient(const Eigen::SparseMatrix& A, /** * @brief Guess-Seidel solver the ir drop. - * - * @param A - * @param b - * @param x0 - * @param tol - * @param max_iter - * @return Eigen::VectorXd + * + * @param A + * @param b + * @param x0 + * @param tol + * @param max_iter + * @return Eigen::VectorXd */ Eigen::VectorXd gaussSeidel(const Eigen::SparseMatrix& A, - const Eigen::VectorXd& b, - const Eigen::VectorXd& x0, double tol, - int max_iter) { - int n = A.rows(); - Eigen::VectorXd x = x0; - Eigen::VectorXd x_prev(n); - double residual; - - std::ofstream residual_file("gauss_seidel_residual.csv", std::ios::trunc); - residual_file << "iteration,residual\n"; - - for (int iter = 0; iter < max_iter; ++iter) { - x_prev = x; - - // Gauss-Seidel iteration - for (int i = 0; i < n; i++) { - double sum = 0.0; - for (Eigen::SparseMatrix::InnerIterator it(A, i); it; ++it) { - if (it.row() != i) { - sum += it.value() * x(it.row()); - } - } - x(i) = (b(i) - sum) / A.coeff(i, i); - - // Apply constraints - x(i) = std::max(x(i), x0(i) * 0.5); + const Eigen::VectorXd& b, const Eigen::VectorXd& x0, + double tol, int max_iter) { + int n = A.rows(); + Eigen::VectorXd x = x0; + Eigen::VectorXd x_prev(n); + double residual; + + std::ofstream residual_file("gauss_seidel_residual.csv", std::ios::trunc); + residual_file << "iteration,residual\n"; + + for (int iter = 0; iter < max_iter; ++iter) { + x_prev = x; + + // Gauss-Seidel iteration + for (int i = 0; i < n; i++) { + double sum = 0.0; + for (Eigen::SparseMatrix::InnerIterator it(A, i); it; ++it) { + if (it.row() != i) { + sum += it.value() * x(it.row()); } + } + x(i) = (b(i) - sum) / A.coeff(i, i); - // Calculate residual - residual = (x - x_prev).norm() / x.norm(); - residual_file << iter + 1 << "," << residual << "\n"; + // Apply constraints + x(i) = std::max(x(i), x0(i) * 0.5); + } - LOG_INFO_EVERY_N(100) << "Gauss-Seidel iteration " << iter + 1 - << " residual: " << residual; + // Calculate residual + residual = (x - x_prev).norm() / x.norm(); + residual_file << iter + 1 << "," << residual << "\n"; - if (residual < tol) { - LOG_INFO << "Gauss-Seidel converged after " << iter + 1 << " iterations"; - break; - } + LOG_INFO_EVERY_N(100) << "Gauss-Seidel iteration " << iter + 1 + << " residual: " << residual; + + if (residual < tol) { + LOG_INFO << "Gauss-Seidel converged after " << iter + 1 << " iterations"; + break; } + } - residual_file.close(); - return x; + residual_file.close(); + return x; } /** @@ -369,40 +368,38 @@ Eigen::VectorXd gaussSeidel(const Eigen::SparseMatrix& A, * @return double */ double calculateConditionNumber(const Eigen::SparseMatrix& A) { - Eigen::MatrixXd denseA = A; - using namespace Spectra; - - Eigen::MatrixXd M = denseA + denseA.transpose(); + Eigen::MatrixXd denseA = A; + using namespace Spectra; - // Construct matrix operation object using the wrapper class DenseSymMatProd - DenseSymMatProd op(M); + Eigen::MatrixXd M = denseA + denseA.transpose(); - // Construct eigen solver object, requesting the largest three eigenvalues - SymEigsSolver> eigs(op, 3, 6); + // Construct matrix operation object using the wrapper class DenseSymMatProd + DenseSymMatProd op(M); - // Initialize and compute - eigs.init(); - // int nconv = eigs.compute(SortRule::LargestAlge); + // Construct eigen solver object, requesting the largest three eigenvalues + SymEigsSolver> eigs(op, 3, 6); - // Retrieve results - Eigen::VectorXd evalues; - if(eigs.info() == CompInfo::Successful) - evalues = eigs.eigenvalues(); + // Initialize and compute + eigs.init(); + // int nconv = eigs.compute(SortRule::LargestAlge); - LOG_INFO << "Largest eigenvalue: " << evalues.maxCoeff(); - LOG_INFO << "Smallest eigenvalue: " << evalues.minCoeff(); + // Retrieve results + Eigen::VectorXd evalues; + if (eigs.info() == CompInfo::Successful) evalues = eigs.eigenvalues(); - return 0.0; + LOG_INFO << "Largest eigenvalue: " << evalues.maxCoeff(); + LOG_INFO << "Smallest eigenvalue: " << evalues.minCoeff(); + return 0.0; } /** * @brief for debug, print top 10 elements of a vector. - * - * @param vec + * + * @param vec */ void PrintTopTenVectorElements(Eigen::VectorXd& vec) { - // for debug + // for debug // Get the top 10 elements of J_vector std::vector> indexed_values; for (int i = 0; i < vec.size(); ++i) { @@ -411,17 +408,16 @@ void PrintTopTenVectorElements(Eigen::VectorXd& vec) { // Sort in descending order std::sort(indexed_values.begin(), indexed_values.end(), - [](const std::pair& a, const std::pair& b) { - return a.first < b.first; - }); + [](const std::pair& a, + const std::pair& b) { return a.first < b.first; }); // Print the top 10 elements LOG_INFO << "Top 10 elements in vec:"; - for (int i = 0; i < std::min(10, static_cast(indexed_values.size())); ++i) { + for (int i = 0; i < std::min(10, static_cast(indexed_values.size())); + ++i) { LOG_INFO << "Index: " << indexed_values[i].second << ", Value: " << indexed_values[i].first; } - } /** @@ -444,7 +440,7 @@ std::vector IRCGSolver::operator()( #if !CUDA_IR_SOLVER Eigen::SparseMatrix A = G_matrix; - + // call the eigen CG solver // Eigen::ConjugateGradient, // Eigen::Lower | Eigen::Upper> @@ -461,26 +457,26 @@ std::vector IRCGSolver::operator()( // Construct the diagonal preconditioner matrix Eigen::SparseMatrix preconditioner(A.rows(), A.cols()); for (int i = 0; i < A.rows(); ++i) { - double diag = A.coeff(i, i); - if (diag != 0) { - preconditioner.insert(i, i) = 1.0 / 1.0; - // LOG_INFO << "Diagonal element at index " << i << " : " << diag; - } else { - preconditioner.insert(i, i) = 0.0; // Handle zero diagonal elements - } + double diag = A.coeff(i, i); + if (diag != 0) { + preconditioner.insert(i, i) = 1.0 / 1.0; + // LOG_INFO << "Diagonal element at index " << i << " : " << diag; + } else { + preconditioner.insert(i, i) = 0.0; // Handle zero diagonal elements + } } LOG_INFO << "Preconditioner matrix constructed."; - - auto B = preconditioner * A; // Apply the preconditioner + + auto B = preconditioner * A; // Apply the preconditioner J_vector = preconditioner * J_vector; // Apply the preconditioner to J_vector - // for debug, calculate the condition number of matrix A + // for debug, calculate the condition number of matrix A // double condition_number = calculateConditionNumber(B); // LOG_INFO << "Condition number of matrix A: " << condition_number; auto max_iter = std::max((int)X0.size(), _max_iteration); - Eigen::VectorXd v_vector = - conjugateGradient(B, J_vector, preconditioner, X0, _tolerance, max_iter, _lambda); + Eigen::VectorXd v_vector = conjugateGradient(B, J_vector, preconditioner, X0, + _tolerance, max_iter, _lambda); v_vector = v_vector / scale; diff --git a/src/operation/iIR/source/ir-solver/IRSolver.hh b/src/operation/iIR/source/ir-solver/IRSolver.hh index ea5901faa4e7cba766149fba62a529298679198b..59d57920b5719ac2be11890ea07a78b0448e66e7 100644 --- a/src/operation/iIR/source/ir-solver/IRSolver.hh +++ b/src/operation/iIR/source/ir-solver/IRSolver.hh @@ -72,19 +72,19 @@ class IRLUSolver : public IRSolver { */ class IRCGSolver : public IRSolver { public: - IRCGSolver(double nominal_voltage) : _nominal_voltage(nominal_voltage) {} - ~IRCGSolver() override = default; + IRCGSolver(double nominal_voltage) : _nominal_voltage(nominal_voltage) {} + ~IRCGSolver() override = default; std::vector operator()( Eigen::Map>& G_matrix, Eigen::VectorXd& J_vector) override; - private: + private: double _nominal_voltage; double _tolerance = 1e-15; int _max_iteration = 1000; - double _lambda = 0; //!< Regularization parameter. + double _lambda = 0; //!< Regularization parameter. }; } // namespace iir \ No newline at end of file diff --git a/src/operation/iIR/source/module/power-netlist/PGNetlist.cc b/src/operation/iIR/source/module/power-netlist/PGNetlist.cc index 697773a4edb48915110386c492230c852125b5cd..9390a4cf01d0e393130dc3abe4d6d9a3ff5e777d 100644 --- a/src/operation/iIR/source/module/power-netlist/PGNetlist.cc +++ b/src/operation/iIR/source/module/power-netlist/PGNetlist.cc @@ -21,11 +21,12 @@ * @version 0.1 * @date 2025-02-22 */ +#include "PGNetlist.hh" + #include #include #include -#include "PGNetlist.hh" #include "iir-rust/IRRustC.hh" #include "log/Log.hh" #include "string/Str.hh" @@ -90,7 +91,7 @@ std::vector IRPGNetlistBuilder::buildBGSegments( // skip the shield wire. continue; } - + for (auto* idb_segment : idb_wire->get_segment_list()) { // line firstly process, we need know line intersect point first. if (!idb_segment->is_via()) { @@ -166,6 +167,9 @@ void IRPGNetlistBuilder::build( auto& special_net_name = special_net->get_net_name(); pg_netlist.set_net_name(special_net_name); + LOG_INFO << "building PG netlist for special net " << special_net_name + << " start"; + std::random_device rd; std::mt19937 gen(rd()); std::uniform_real_distribution<> dis(0.0, _c_instance_row_resistance * 0.1); @@ -176,12 +180,13 @@ void IRPGNetlistBuilder::build( buildBGSegments(special_net, line_segment_num, segment_widths); // FIXME(to taosimin), should not hard code the instance pin layer. - unsigned instance_pin_layer = 1; + unsigned instance_pin_layer = 2; // Firstly, get the wire topo point in line segment. std::set> pg_points; std::map> segment_to_point; - std::map intersect_segment_one_layer; // the segment one layer need connect. + std::map + intersect_segment_one_layer; // the segment one layer need connect. std::map coordy_to_segment_id; // coord y to segment id, for locate // instance pin segment. for (unsigned i = 0; i < line_segment_num; ++i) { @@ -252,7 +257,7 @@ void IRPGNetlistBuilder::build( auto distance = std::abs(x1 - x2) + std::abs(y1 - y2); // pg node layer from one first, we need minus one. double resistance = - calc_resistance(node1->get_layer_id(), distance, width_dbu); + calc_resistance(node1->get_layer_id() - 1, distance, width_dbu); return resistance; }; @@ -282,8 +287,24 @@ void IRPGNetlistBuilder::build( // of the segment. for (auto [seg_id1, seg_id2] : intersect_segment_one_layer) { // connect the last point of seg_id1 and first point of seg_id2. - auto* node1 = *(segment_to_point[seg_id1].rbegin()); // Get last element of first segment - auto* node2 = *(segment_to_point[seg_id2].begin()); // Get first element of second segment + auto* node1 = *(segment_to_point[seg_id1] + .rbegin()); // Get last element of first segment + LOG_INFO_IF(!node1) << "The nodes of segment " << seg_id1 << " (" + << bg_segments[seg_id1].first.get<0>() << " " + << bg_segments[seg_id1].first.get<1>() << " " + << bg_segments[seg_id1].first.get<2>() << ")" + << " is nullptr."; + auto* node2 = *(segment_to_point[seg_id2] + .begin()); // Get first element of second segment + LOG_INFO_IF(!node2) << "The nodes of segment " << seg_id2 << " (" + << bg_segments[seg_id2].first.get<0>() << " " + << bg_segments[seg_id2].first.get<1>() << " " + << bg_segments[seg_id2].first.get<2>() << ")" + << " is nullptr."; + + if (!node1 || !node2) { + continue; + } if (node1->get_coord().first == node2->get_coord().first) { LOG_FATAL_IF(node1->get_coord().second > node2->get_coord().second) @@ -292,14 +313,13 @@ void IRPGNetlistBuilder::build( LOG_FATAL_IF(node1->get_coord().first > node2->get_coord().first) << "node1 coord x should be less than node2 coord x."; } - + // Add edge between intersecting segments auto& pg_edge = pg_netlist.addEdge(node1, node2); auto width_dbu = segment_widths[seg_id1]; - double resistance = - calc_segment_resistance(node1, node2, width_dbu); - + double resistance = calc_segment_resistance(node1, node2, width_dbu); + double random_value = dis(gen); pg_edge.set_resistance(resistance + random_value); } @@ -340,8 +360,8 @@ void IRPGNetlistBuilder::build( auto& pg_edge = pg_netlist.addEdge(via_start_node, via_end_node); double random_value = dis(gen); - // TODO(to taosimin), hard code the via resistance, need know the resistance - // of via. + // TODO(to taosimin), hard code the via resistance, need know the + // resistance of via. double via_resistance = getViaResistance(via_bottom_layer); pg_edge.set_resistance(via_resistance + random_value); } @@ -437,7 +457,7 @@ void IRPGNetlistBuilder::build( idb::IdbLayerShape* port_layer_shape = nullptr; idb::IdbCoordinate middle_point; int layer_id = 0; - if (io_pin->get_port_box_list().size() > 0) { + if (io_pin->get_port_box_list().size() > 1) { port_layer_shape = io_pin->get_port_box_list().front(); // connect io node to the segment node. auto layer_name = port_layer_shape->get_layer()->get_name(); @@ -445,6 +465,7 @@ void IRPGNetlistBuilder::build( auto bounding_box = port_layer_shape->get_bounding_box(); middle_point = bounding_box.get_middle_point(); } else { + // for idb, maybe need chooset to term to get the port layer shape. auto* io_port = io_pin->get_term()->get_port_list().front(); if (io_port->get_layer_shape().size() == 0) { LOG_FATAL << "io port layer shape is empty"; @@ -500,13 +521,18 @@ void IRPGNetlistBuilder::build( << " bump node location: " << middle_point.get_x() / _dbu << " " << middle_point.get_y() / _dbu << " " << getLayerName(layer_id); - IRNodeLoc bump_node_loc{{middle_point.get_x() / (double)_dbu, middle_point.get_y() / (double)_dbu}, getLayerName(layer_id)}; + IRNodeLoc bump_node_loc{{middle_point.get_x() / (double)_dbu, + middle_point.get_y() / (double)_dbu}, + getLayerName(layer_id)}; _net_bump_node_locs[special_net_name] = bump_node_loc; LOG_INFO << "instance pin edge num: " << pg_netlist.getEdgeNum() - via_edge_num - line_edge_num; LOG_INFO << "total edge num: " << pg_netlist.getEdgeNum(); + LOG_INFO << "building PG netlist for special net " << special_net_name + << " end"; + // for debug. // if (special_net_name == "VDD") { // pg_netlist.printToYaml( @@ -539,10 +565,11 @@ void IRPGNetlistBuilder::createRustPGNetlist() { * @brief estimate rc for the pg netlist. * */ -void IRPGNetlistBuilder::createRustRCData() { +unsigned IRPGNetlistBuilder::createRustRCData() { auto* rust_pg_netlist_vec_ptr = _rust_pg_netlists.data(); auto len = _rust_pg_netlists.size(); _rust_rc_data = create_rc_data(rust_pg_netlist_vec_ptr, len); + return 1; } /** @@ -558,30 +585,30 @@ void IRPGNetlistBuilder::calcResistanceFromBumpNode(std::string net_name) { /** * @brief get the via resistance, maybe need calc by layer shape. - * - * @param bottom_layer_id - * @return double + * + * @param bottom_layer_id + * @return double */ double IRPGNetlistBuilder::getViaResistance(unsigned bottom_layer_id) { double via_resistance = _c_via_resistance; - if (bottom_layer_id == 1) { + if (bottom_layer_id == 1) { via_resistance = 7.597; - } else if ( bottom_layer_id == 2) { + } else if (bottom_layer_id == 2) { via_resistance = 3.799; - } else if ( bottom_layer_id == 3) { + } else if (bottom_layer_id == 3) { via_resistance = 3.799; - } else if ( bottom_layer_id == 4) { + } else if (bottom_layer_id == 4) { via_resistance = 3.799; - } else if ( bottom_layer_id == 5) { + } else if (bottom_layer_id == 5) { via_resistance = 3.799; - } else if ( bottom_layer_id == 6) { + } else if (bottom_layer_id == 6) { via_resistance = 3.7997; - } else if ( bottom_layer_id == 7) { + } else if (bottom_layer_id == 7) { via_resistance = 0.085; - } else if ( bottom_layer_id == 8) { + } else if (bottom_layer_id == 8) { via_resistance = 0.017; - } + } return via_resistance; } diff --git a/src/operation/iIR/source/module/power-netlist/PGNetlist.hh b/src/operation/iIR/source/module/power-netlist/PGNetlist.hh index af2359603ba71aacc35bff7aa86e5883e8ac93bb..eb44e4ba96f7491976c7aad2cbb51970b5d97b66 100644 --- a/src/operation/iIR/source/module/power-netlist/PGNetlist.hh +++ b/src/operation/iIR/source/module/power-netlist/PGNetlist.hh @@ -27,10 +27,10 @@ #include #include #include -#include -#include #include #include +#include +#include #include "IdbLayer.h" #include "IdbLayout.h" @@ -42,7 +42,6 @@ #include "lef_service.h" #include "log/Log.hh" - namespace bg = boost::geometry; namespace bgi = boost::geometry::index; @@ -82,22 +81,20 @@ class IRPGNode { void set_is_via() { _is_via = true; } bool is_via() const { return _is_via; } - private: - IRNodeCoord _coord; //!< The coord of the node. - int _layer_id; //!< The layer id of the node. - int _node_id = -1; //!< The node id of the pg nodes. - bool _is_instance_pin = false; //!< The node is instance VDD/GND. - bool _is_bump = false; //!< The node is bump VDD/GND. - bool _is_via = false; //!< The node is via. - - const char* _node_name = nullptr; //!< The name of the node. - + IRNodeCoord _coord; //!< The coord of the node. + int _layer_id; //!< The layer id of the node. + int _node_id = -1; //!< The node id of the pg nodes. + bool _is_instance_pin = false; //!< The node is instance VDD/GND. + bool _is_bump = false; //!< The node is bump VDD/GND. + bool _is_via = false; //!< The node is via. + + const char* _node_name = nullptr; //!< The name of the node. }; /** * @brief node comparator for store IR Node according to the coord order. - * + * */ struct IRNodeComparator { bool operator()(const IRPGNode* lhs, const IRPGNode* rhs) const { @@ -112,8 +109,9 @@ struct IRNodeComparator { }; /** - * @brief node comparator for store IR Node according to the row order for row edge connected. - * + * @brief node comparator for store IR Node according to the row order for row + * edge connected. + * */ struct IRNodeRowComparator { bool operator()(const IRPGNode* lhs, const IRPGNode* rhs) const { @@ -146,7 +144,7 @@ class IRPGEdge { int64_t _node1; //!< The first node id. int64_t _node2; //!< The second node id. - double _resistance = 0.0; //!< The edge resistance. + double _resistance = 0.0; //!< The edge resistance. }; /** @@ -184,9 +182,7 @@ class IRPGNetlist { } auto& get_nodes() { return _nodes; } auto& get_nodes_image() { return _nodes_image; } - IRPGNode* getNode(unsigned index) { - return _nodes_image[index]; - } + IRPGNode* getNode(unsigned index) { return _nodes_image[index]; } auto getEdgeNode(IRPGEdge& pg_edge) { auto node1_id = pg_edge.get_node1(); @@ -209,31 +205,31 @@ class IRPGNetlist { _node_id_to_name[node_id] = std::move(name); } auto& get_node_id_to_name() { return _node_id_to_name; } - auto& getNodeName(unsigned node_id) { - return _node_id_to_name[node_id]; - } + auto& getNodeName(unsigned node_id) { return _node_id_to_name[node_id]; } - void addBumpNode(IRPGNode* bump_node) { - _bump_nodes.push_back(bump_node); - } + void addBumpNode(IRPGNode* bump_node) { _bump_nodes.push_back(bump_node); } auto& get_bump_nodes() { return _bump_nodes; } void printToYaml(std::string yaml_path); private: - std::list _nodes; //!< The nodes of the netlist. - std::vector _nodes_image; //!< The nodes image for fast access. - std::map, IRPGNode*> _nodes_map; //!< The nodes map for fast access. + std::list _nodes; //!< The nodes of the netlist. + std::vector _nodes_image; //!< The nodes image for fast access. + std::map, IRPGNode*> + _nodes_map; //!< The nodes map for fast access. std::vector _edges; //!< The edges of the netlist. - std::vector _bump_nodes; //!< The bump nodes of the netlist. + std::vector _bump_nodes; //!< The bump nodes of the netlist. - std::map _node_id_to_name; //!< The node id to node name. + std::map + _node_id_to_name; //!< The node id to node name. std::string _net_name; }; -using IRNodeLoc = std::pair, std::string>; //!< The node location type, coord and layer id. +using IRNodeLoc = + std::pair, + std::string>; //!< The node location type, coord and layer id. /** * @brief The pg netlist builder. @@ -257,12 +253,14 @@ class IRPGNetlistBuilder { auto& get_rust_pg_netlists() { return _rust_pg_netlists; } std::vector buildBGSegments(idb::IdbSpecialNet* special_net, - unsigned& line_segment_num, std::vector& segment_widths); + unsigned& line_segment_num, + std::vector& segment_widths); - void build(idb::IdbSpecialNet* special_net, idb::IdbPin* io_pin, - std::function calc_resistance); + void build( + idb::IdbSpecialNet* special_net, idb::IdbPin* io_pin, + std::function calc_resistance); void createRustPGNetlist(); - void createRustRCData(); + unsigned createRustRCData(); auto* get_rust_rc_data() const { return _rust_rc_data; } @@ -307,8 +305,8 @@ class IRPGNetlistBuilder { double getViaResistance(unsigned bottom_layer_id); void clearRTree() { - _rtree.clear(); // Clear all data in rtree - } + _rtree.clear(); // Clear all data in rtree + } auto& get_net_bump_node_locs() { return _net_bump_node_locs; } @@ -316,17 +314,19 @@ class IRPGNetlistBuilder { bgi::rtree> _rtree; double _c_via_resistance = 0.01; double _c_instance_row_resistance = 0.01; - double _dbu = 2000; //!< The dbu for the design. + double _dbu = 2000; //!< The dbu for the design. - std::map _layer_name_to_id; //!< The layer name to id map. + std::map + _layer_name_to_id; //!< The layer name to id map. - std::set _instance_names; //!< The instance have power. + std::set _instance_names; //!< The instance have power. - std::list _pg_netlists; //!< The builded pg netlist. - std::vector _rust_pg_netlists; //!< The rust pg netlist. + std::list _pg_netlists; //!< The builded pg netlist. + std::vector _rust_pg_netlists; //!< The rust pg netlist. const void* _rust_rc_data = nullptr; - std::map _net_bump_node_locs; //!< The net bump node locs. + std::map + _net_bump_node_locs; //!< The net bump node locs. }; } // namespace iir \ No newline at end of file diff --git a/src/operation/iNO/README.md b/src/operation/iNO/README.md index 782a7ead3181f559f3d965ea15bf169a5e4d9a5e..ae08bed3cb421b78575ae4c7b94a7edb981c6c66 100644 --- a/src/operation/iNO/README.md +++ b/src/operation/iNO/README.md @@ -1,33 +1,34 @@ -# iNO 功能文档 +# iNO: Netlist Optimization -> ## 概述 -NO的全称为Netlist Optimization,网表优化。iNO当前支持扇出优化,通过插入缓冲器使线网满足最大扇出约束。 +## Overview -> ## iNO使用示例 +NO stands for Netlist Optimization. Currently, iNO supports fanout optimization, which makes the net meet the maximum fanout constraint by inserting buffers. -用户需要在Config文件中指定最大扇出(fanout)约束、使用的缓冲器类型。例如 +## iNO Usage Example + +Users need to specify the maximum fanout constraint and the type of buffer used in the Config file. For example, ``` "insert_buffer": "LVTX_4", "max_fanout": 30 ``` -1.在Tcl文件中设置Config文件 +1. Set the Config file in the Tcl file -`run_no_fixfanout -config ./iEDA_config/no_default_config_fixfanout.json` +`run_no_fixfanout -config./iEDA_config/no_default_config_fixfanout.json` -2.使用iEDA运行tcl文件 +2. Use iEDA to run the tcl file -`./iEDA -script ./script/iNO_script/run_iNO_fix_fanout.tcl` +`./iEDA -script./script/iNO_script/run_iNO_fix_fanout.tcl` -### 报告输出 +### Report Output -在Config文件中可设置优化结果的报告输出路径: +In the Config file, the report output path of the optimization result can be set: ``` "report_file": "path" ``` -fanout优化报告输出示例: +Example of fanout optimization report output: ``` [Result: ] Find 0 Net with fanout violation. [Result: ] Insert 0 Buffers. diff --git a/src/operation/iPA/CMakeLists.txt b/src/operation/iPA/CMakeLists.txt index 2a11115bd7eacd6654e0c89eae6f26d8deb45471..592c3e83c2369969e563d25e2ee41b244af51450 100644 --- a/src/operation/iPA/CMakeLists.txt +++ b/src/operation/iPA/CMakeLists.txt @@ -26,9 +26,9 @@ include_directories(SYSTEM ${HOME_THIRDPARTY}) include(${HOME_CMAKE}/operation/ista.cmake) include_directories(${PROJECT_SOURCE_DIR}/src/operation) -include_directories(${PROJECT_SOURCE_DIR}/src/operation/iPW) -include_directories(${PROJECT_SOURCE_DIR}/src/operation/iPW/source) -include_directories(${PROJECT_SOURCE_DIR}/src/operation/iPW/source/module) +include_directories(${PROJECT_SOURCE_DIR}/src/operation/iPA) +include_directories(${PROJECT_SOURCE_DIR}/src/operation/iPA/source) +include_directories(${PROJECT_SOURCE_DIR}/src/operation/iPA/source/module) include_directories(${HOME_THIRDPARTY}/pybind11) diff --git a/src/operation/iPA/README.md b/src/operation/iPA/README.md index 5d58ad4346bd6422394e246617ef3a8fba54ce6a..756d8624e6cde69f09561cbfe9391a8f6536fab0 100644 --- a/src/operation/iPA/README.md +++ b/src/operation/iPA/README.md @@ -1,4 +1,4 @@ -# User guide of iPower +# iPA: Power Analysis ## Introduction to the ipower diff --git a/src/operation/iPA/api/CMakeLists.txt b/src/operation/iPA/api/CMakeLists.txt index f65cb7115e943038bc634ae80aab585c97e39bf0..602400e6cecdd310a35eeeac696a265a33b13cfb 100644 --- a/src/operation/iPA/api/CMakeLists.txt +++ b/src/operation/iPA/api/CMakeLists.txt @@ -30,5 +30,5 @@ endif() target_include_directories( power PUBLIC ${PROJECT_SOURCE_DIR}/src/operation - ${PROJECT_SOURCE_DIR}/src/operation/iPW/source/module + ${PROJECT_SOURCE_DIR}/src/operation/iPA/source/module ${HOME_OPERATION}/iSTA) diff --git a/src/operation/iPA/api/Power.cc b/src/operation/iPA/api/Power.cc index fc598c702738099b4df1ee9cd4d59d0acfa49cee..0eb28d527bfa05711b1a82ff70ea2544a071fb8b 100644 --- a/src/operation/iPA/api/Power.cc +++ b/src/operation/iPA/api/Power.cc @@ -27,7 +27,6 @@ #include #include -#include "Power.hh" #include "json/json.hpp" #include "ops/annotate_toggle_sp/AnnotateToggleSP.hh" #include "ops/build_graph/PwrBuildGraph.hh" @@ -490,12 +489,17 @@ unsigned Power::reportSummaryPower(const char* rpt_file_name, LOG_INFO << "\n" << report_tbl->c_str(); + Time::stop(); + double elapsed_time = Time::elapsedTime(); + LOG_INFO << "iPA total elapsed time: " << elapsed_time << " seconds"; + auto close_file = [](std::FILE* fp) { std::fclose(fp); }; std::unique_ptr f( std::fopen(rpt_file_name, "w"), close_file); std::fprintf(f.get(), "Generate the report at %s\n", Time::getNowWallTime()); + std::fprintf(f.get(), "iPA elapsed time: %.2f seconds.\n", elapsed_time); std::map analysis_mode_to_string = { {PwrAnalysisMode::kAveraged, "Averaged"}, @@ -556,7 +560,7 @@ unsigned Power::reportSummaryPowerJSON(const char* rpt_file_name, report_power(this); auto& report_summary_data = report_power.get_report_summary_data(); nlohmann::json json_report = nlohmann::json::object(); - auto &summary_json = json_report["summary"] = nlohmann::json::array(); + auto& summary_json = json_report["summary"] = nlohmann::json::array(); // lambda for print power data float to string. auto data_str = [](double data) { return Str::printf("%.3e", data); }; @@ -1070,6 +1074,9 @@ unsigned Power::reportPower(bool is_copy) { double time_delta = stats.elapsedRunTime(); LOG_INFO << "power report time elapsed " << time_delta << "s"; + // restart timer. + Time::start(); + return 1; } @@ -1156,8 +1163,7 @@ unsigned Power::readPGSpef(const char* spef_file) { */ unsigned Power::reportIRDropTable(const char* rpt_file_name) { auto create_report_table = [](const char* title) { - auto report_tbl = - std::make_unique(title); + auto report_tbl = std::make_unique(title); (*report_tbl) << TABLE_HEAD; /* Fill each cell with operator[] */ @@ -1168,13 +1174,16 @@ unsigned Power::reportIRDropTable(const char* rpt_file_name) { return report_tbl; }; + Time::stop(); + double elapsed_time = Time::elapsedTime(); + LOG_INFO << "iIR total elapsed time: " << elapsed_time << " seconds"; auto close_file = [](std::FILE* fp) { std::fclose(fp); }; std::unique_ptr f( std::fopen(rpt_file_name, "w"), close_file); - std::fprintf(f.get(), "Generate the report at %s\n\n", - Time::getNowWallTime()); + std::fprintf(f.get(), "Generate the report at %s\n", Time::getNowWallTime()); + std::fprintf(f.get(), "iIR elapsed time: %.2f seconds.\n\n", elapsed_time); auto pg_net_bump_node_loc = _ir_analysis.get_net_bump_node_locs(); for (auto [pg_net_name, net_bump_node_loc] : pg_net_bump_node_loc) { @@ -1186,7 +1195,7 @@ unsigned Power::reportIRDropTable(const char* rpt_file_name) { double nominal_voltage = getNominalVoltage(); std::fprintf(f.get(), "Nominal Voltage: %.3f V\n", nominal_voltage); - + auto data_str = [](double data) { return Str::printf("%.3e", data); }; auto net_to_instance_ir_drop = getNetInstanceIRDrop(); diff --git a/src/operation/iPA/api/Power.hh b/src/operation/iPA/api/Power.hh index c4be4580b89dac30a0221385225bf9e4f56e70be..69348c1e4526e9c887993bd2e8520e44c18a740a 100644 --- a/src/operation/iPA/api/Power.hh +++ b/src/operation/iPA/api/Power.hh @@ -28,11 +28,11 @@ #include "core/PwrGraph.hh" #include "core/PwrGroupData.hh" #include "core/PwrSeqGraph.hh" -#include "include/PwrConfig.hh" -#include "ops/read_vcd/RustVCDParserWrapper.hh" #include "iIR/api/iIR.hh" #include "iIR/source/module/power-netlist/PGNetlist.hh" +#include "include/PwrConfig.hh" #include "json/json.hpp" +#include "ops/read_vcd/RustVCDParserWrapper.hh" using namespace iir; @@ -51,10 +51,14 @@ class Power { static Power* getOrCreatePower(StaGraph* sta_graph); static void destroyPower(); - void set_design_work_space(const char* design_work_space) { _design_work_space = design_work_space; } + void set_design_work_space(const char* design_work_space) { + _design_work_space = design_work_space; + } const char* get_design_work_space() { return _design_work_space.c_str(); } - void set_default_toggle(double default_toggle) { _default_toggle = default_toggle; } + void set_default_toggle(double default_toggle) { + _default_toggle = default_toggle; + } double get_default_toggle() { return _default_toggle; } void enableJsonReport() { _is_json_report_enabled = true; } @@ -75,11 +79,11 @@ class Power { void set_rust_pg_rc_data(const void* rust_pg_rc_data) { _rust_pg_rc_data = rust_pg_rc_data; - // set rc data. + // set rc data. _ir_analysis.set_rc_data(_rust_pg_rc_data); } auto* get_rust_pg_rc_data() { return _rust_pg_rc_data; } - + auto& get_leakage_powers() { return _leakage_powers; } auto& get_internal_powers() { return _internal_powers; } auto& get_switch_powers() { return _switch_powers; } @@ -148,9 +152,7 @@ class Power { _rust_pg_rc_data = nullptr; } - double getNominalVoltage() { - return _ir_analysis.get_nominal_voltage(); - } + double getNominalVoltage() { return _ir_analysis.get_nominal_voltage(); } auto& getNetInstanceIRDrop() { return _ir_analysis.get_net_to_instance_ir_drop(); @@ -163,7 +165,7 @@ class Power { void setBumpNodeLocs( const std::map& net_bump_node_locs) { _ir_analysis.set_net_bump_node_locs(net_bump_node_locs); - } + } unsigned runIRAnalysis(std::string power_net_name); unsigned reportIRDropTable(const char* rpt_file_name); unsigned reportIRDropCSV(const char* rpt_file_name, std::string net_name); @@ -174,9 +176,9 @@ class Power { std::map displayInstancePowerMap(); private: - std::string _design_work_space; //!< The power report work space. + std::string _design_work_space; //!< The power report work space. std::optional> _backup_work_dir; - double _default_toggle = 0.02; //!< The default toggle value. + double _default_toggle = 0.02; //!< The default toggle value. PwrGraph _power_graph; //< The power graph, mapped to sta graph. PwrSeqGraph _power_seq_graph; //!< The power sequential graph, vertex is @@ -194,8 +196,8 @@ class Power { std::map> _type_to_group_data; //!< The mapping of type to group data. - iIR _ir_analysis; //!< The IR Drop analysis top. - const void* _rust_pg_rc_data = nullptr; //!< The rust power/ground rc data. + iIR _ir_analysis; //!< The IR Drop analysis top. + const void* _rust_pg_rc_data = nullptr; //!< The rust power/ground rc data. bool _is_json_report_enabled = false; //!< Whether to enable json report. diff --git a/src/operation/iPA/api/PowerEngine.cc b/src/operation/iPA/api/PowerEngine.cc index 330d7dabf2e76869efa45c54ea3af7cae97aa2ed..9c206e27b4ac7d3b44b22f98f4f5025ef2552b50 100644 --- a/src/operation/iPA/api/PowerEngine.cc +++ b/src/operation/iPA/api/PowerEngine.cc @@ -22,10 +22,11 @@ * @date 2024-02-26 * */ +#include "PowerEngine.hh" + #include #include -#include "PowerEngine.hh" #include "ThreadPool/ThreadPool.h" #ifdef USE_GPU #include "gpu-kernel/power_kernel.cuh" @@ -378,7 +379,8 @@ std::vector PowerEngine::buildMacroConnectionMapWithGPU( << " is not equal to seq graph arc num " << seq_graph.getSeqArcNum(); std::size_t output_connection_size = seq_arcs.size(); - std::vector out_connection_points(output_connection_size); + std::vector out_connection_points( + output_connection_size); int connection_point_num = connection_points.size(); auto& seq_vertexes = seq_graph.get_vertexes(); @@ -470,25 +472,32 @@ std::vector PowerEngine::buildMacroConnectionMapWithGPU( /** * @brief build pg net wire topology. - * - * @return unsigned + * + * @return unsigned */ unsigned PowerEngine::buildPGNetWireTopo() { LOG_INFO << "build pg net wire topo start"; - + // set the instance names for build wire topo skip some no power instance. - std::vector instance_power_data = _ipower->getInstancePowerData(); + std::vector instance_power_data = + _ipower->getInstancePowerData(); std::set instance_names; - std::ranges::for_each(instance_power_data, [&instance_names](auto& instance_power) { - std::string instance_name = instance_power._instance_name; - instance_names.insert(std::move(instance_name)); - }); + std::ranges::for_each( + instance_power_data, [&instance_names](auto& instance_power) { + std::string instance_name = instance_power._instance_name; + instance_names.insert(std::move(instance_name)); + }); _pg_netlist_builder.set_instance_names(std::move(instance_names)); auto* idb_adapter = dynamic_cast(_timing_engine->get_db_adapter()); auto* idb_builder = idb_adapter->get_idb(); + // for debug + // std::string def_file_path = "./output.def"; + // idb_builder->saveDef(def_file_path); + // LOG_INFO << "save def file to " << def_file_path; + // set layer name to id. IdbLayout* idb_layout = idb_builder->get_lef_service()->get_layout(); vector& routing_layers = @@ -506,10 +515,13 @@ unsigned PowerEngine::buildPGNetWireTopo() { _pg_netlist_builder.set_dbu(dbu); std::function calc_resistance = - [idb_adapter, dbu](unsigned layer_id, unsigned distance_dbu, unsigned width_dbu) -> double { + [idb_adapter, dbu](unsigned layer_id, unsigned distance_dbu, + unsigned width_dbu) -> double { double wire_length = double(distance_dbu) / dbu; double width = double(width_dbu) / dbu; - double resistance = idb_adapter->getResistance(layer_id, wire_length, width); + int routing_layer_1st = 1; // 1st routing layer id is 1. + double resistance = + idb_adapter->getResistance(layer_id, wire_length, width, routing_layer_1st); resistance *= c_resistance_coef; return resistance; @@ -549,11 +561,11 @@ unsigned PowerEngine::buildPGNetWireTopo() { /** * @brief reset ir data for rerun ir analysis. - * + * */ void PowerEngine::resetIRAnalysisData() { _pg_netlist_builder.clearRTree(); - + IRPGNetlistBuilder pg_netlist_builder; _pg_netlist_builder = std::move(pg_netlist_builder); @@ -562,10 +574,11 @@ void PowerEngine::resetIRAnalysisData() { /** * @brief get instance ir drop map. - * - * @return std::map + * + * @return std::map */ -std::map PowerEngine::getInstanceIRDrop(std::string power_net_name) { +std::map PowerEngine::getInstanceIRDrop( + std::string power_net_name) { std::map instance_to_ir_drop; auto instance_pin_to_ir_drop = _ipower->getInstanceIRDrop(power_net_name); @@ -581,14 +594,14 @@ std::map PowerEngine::getInstanceIRDrop(std::string power_net instance_to_ir_drop[sta_inst] = inst_ir_drop; } - + return instance_to_ir_drop; } /** * @brief function to display ir drop map. - * - * @return std::map + * + * @return std::map */ std::map PowerEngine::displayIRDropMap() { LOG_INFO << "display IR Drop map start"; @@ -598,7 +611,6 @@ std::map PowerEngine::displayIRDropMap() { auto instance_to_ir_drop = getInstanceIRDrop(); for (auto& [sta_inst, inst_ir_drop] : instance_to_ir_drop) { - auto coord = sta_inst->get_coordinate().value(); coord_to_ir_drop_map[coord] = inst_ir_drop; diff --git a/src/operation/iPA/api/PowerEngine.hh b/src/operation/iPA/api/PowerEngine.hh index 38b2d094d1bab46aa031bfb2e3382c8b03a44eb3..8f13bb80ce8330c3ead3ee6575ad9643a7fb924c 100644 --- a/src/operation/iPA/api/PowerEngine.hh +++ b/src/operation/iPA/api/PowerEngine.hh @@ -43,14 +43,13 @@ struct ClusterConnection { unsigned _hop; }; - /** * @brief macro connection for iMP. * */ struct MacroConnection { - const char* _src_macro_name; - const char* _dst_macro_name; + const char *_src_macro_name; + const char *_dst_macro_name; std::vector _stages_each_hop; unsigned _hop; }; @@ -82,10 +81,12 @@ class PowerEngine { std::vector buildMacroConnectionMap(unsigned max_hop); unsigned buildPGNetWireTopo(); - unsigned readPGSpef(const char* spef_file) { return _ipower->readPGSpef(spef_file); } + unsigned readPGSpef(const char *spef_file) { + return _ipower->readPGSpef(spef_file); + } void resetIRAnalysisData(); - auto* getRustPGRCData() { return _ipower->get_rust_pg_rc_data(); } + auto *getRustPGRCData() { return _ipower->get_rust_pg_rc_data(); } unsigned runIRAnalysis(std::string power_net_name) { if (!getRustPGRCData()) { buildPGNetWireTopo(); @@ -93,18 +94,18 @@ class PowerEngine { auto net_bump_node_locs = _pg_netlist_builder.get_net_bump_node_locs(); _ipower->setBumpNodeLocs(net_bump_node_locs); } + return _ipower->runIRAnalysis(power_net_name); } - std::map getInstanceIRDrop(std::string power_net_name = "VDD"); + std::map getInstanceIRDrop( + std::string power_net_name = "VDD"); std::map displayPowerMap() { return _ipower->displayInstancePowerMap(); } std::map displayIRDropMap(); - unsigned reportIRAnalysis() { - return _ipower->reportIRAnalysis(); - } + unsigned reportIRAnalysis() { return _ipower->reportIRAnalysis(); } #ifdef USE_GPU std::vector buildMacroConnectionMapWithGPU(unsigned max_hop); diff --git a/src/operation/iPA/main.cc b/src/operation/iPA/main.cc index 9fa088e19f2f21b6be7a7e412fe2c21b2dc8d43a..2da6a05dce4b0205f89d5efe98de23ee448a908a 100644 --- a/src/operation/iPA/main.cc +++ b/src/operation/iPA/main.cc @@ -75,16 +75,9 @@ void sig_handler(int sig) { } int main(int argc, char** argv) { - // signal(SIGINT, sig_handler); - // signal(SIGILL, sig_handler); - // signal(SIGABRT, sig_handler); - // signal(SIGFPE, sig_handler); - // signal(SIGSEGV, sig_handler); - // signal(SIGTERM, sig_handler); - // signal(SIGQUIT, sig_handler); - // signal(SIGKILL, sig_handler); - Log::init(argv); + // Start the timer + Time::start(); std::string hello_info = "\033[49;32m********************************\n" diff --git a/src/operation/iPA/source/module/include/PwrConfig.hh b/src/operation/iPA/source/module/include/PwrConfig.hh index 51281792206c631f668c0963e838a48259e79d58..d2b3c660c4e34ae3db64333bd3b2801387ee30f5 100644 --- a/src/operation/iPA/source/module/include/PwrConfig.hh +++ b/src/operation/iPA/source/module/include/PwrConfig.hh @@ -39,8 +39,9 @@ constexpr double c_default_clock_toggle = 2.0; constexpr double c_default_clock_sp = 0.5; constexpr double c_switch_power_K = 0.5; -constexpr double c_default_toggle = 0.02; // time unit: ns, set by tcl cmd, not used anymore. -constexpr double c_default_period = 10; // time unit: ns +constexpr double c_default_toggle = + 0.02; // time unit: ns, set by tcl cmd, not used anymore. +constexpr double c_default_period = 10; // time unit: ns constexpr double c_default_toggle_relative_clk = 0.125; // time unit: period // for estimate IR diff --git a/src/operation/iPA/source/python-api/PythonPower.cc b/src/operation/iPA/source/python-api/PythonPower.cc index bacaddf7d80cf526578545e0fc655bdba8fc19e0..ffd7020631d0532ee473c464a2e982971b3e547b 100644 --- a/src/operation/iPA/source/python-api/PythonPower.cc +++ b/src/operation/iPA/source/python-api/PythonPower.cc @@ -33,6 +33,7 @@ using namespace ista; namespace ipower { PYBIND11_MODULE(ipower_cpp, m) { + // sta python interface m.def("set_design_workspace", set_design_workspace, ("design_workspace")); m.def("read_lef_def", read_lef_def, ("lef_files"), ("def_file")); m.def("read_netlist", read_netlist, ("file_name")); @@ -45,6 +46,19 @@ PYBIND11_MODULE(ipower_cpp, m) { m.def("display_timing_tns_map", display_timing_tns_map); m.def("display_slew_map", display_slew_map); + // get wire timing data + py::class_(m, "WireTimingData") + .def_readwrite("from_node_name", &StaWireTimingData::_from_node_name) + .def_readwrite("to_node_name", &StaWireTimingData::_to_node_name) + .def_readwrite("wire_resistance", &StaWireTimingData::_wire_resistance) + .def_readwrite("wire_capacitance", &StaWireTimingData::_wire_capacitance) + .def_readwrite("wire_from_slew", &StaWireTimingData::_wire_from_slew) + .def_readwrite("wire_to_slew", &StaWireTimingData::_wire_to_slew) + .def_readwrite("wire_delay", &StaWireTimingData::_wire_delay); + + m.def("get_wire_timing_data", get_wire_timing_data, py::arg("n_worst_path_per_clock")); + + // power python interface m.def("read_vcd", &read_vcd, py::arg("vcd_file"), py::arg("top_instance_name")); m.def("read_pg_spef", &read_pg_spef, py::arg("pg_spef_file")); m.def("report_power", &report_power); diff --git a/src/operation/iPA/source/shell-cmd/PowerShellCmd.hh b/src/operation/iPA/source/shell-cmd/PowerShellCmd.hh index 803c84c883229c0eea650a8662f65e71dc520177..ca04728e4efbd5603c442b21227d4ce5f4017753 100644 --- a/src/operation/iPA/source/shell-cmd/PowerShellCmd.hh +++ b/src/operation/iPA/source/shell-cmd/PowerShellCmd.hh @@ -1,16 +1,16 @@ // *************************************************************************************** // Copyright (c) 2023-2025 Peng Cheng Laboratory -// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences -// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of +// Sciences Copyright (c) 2023-2025 Beijing Institute of Open Source Chip // // iEDA is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. You may obtain a copy of Mulan PSL v2 at: // http://license.coscl.org.cn/MulanPSL2 // -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // // See the Mulan PSL v2 for more details. // *************************************************************************************** @@ -31,10 +31,10 @@ namespace ipower { using ieda::ScriptEngine; using ieda::TclCmd; +using ieda::TclDoubleOption; +using ieda::TclIntOption; using ieda::TclOption; using ieda::TclStringOption; -using ieda::TclIntOption; -using ieda::TclDoubleOption; using ieda::TclSwitchOption; /** @@ -65,10 +65,10 @@ class CmdReadVcd : public TclCmd { /** * @brief read_pg_spef cmd. - * + * */ class CmdReadPGSpef : public TclCmd { -public: + public: explicit CmdReadPGSpef(const char* cmd_name); ~CmdReadPGSpef() override = default; @@ -91,16 +91,15 @@ class CmdReportPower : public TclCmd { /** * @brief report_ir_drop cmd. - * + * */ class CmdReportIRDrop : public TclCmd { -public: + public: explicit CmdReportIRDrop(const char* cmd_name); ~CmdReportIRDrop() override = default; unsigned check() override; unsigned exec() override; - }; } // namespace ipower diff --git a/src/operation/iPA/test/PowerTest.cc b/src/operation/iPA/test/PowerTest.cc index 360cad891fb13cc5e712516f361dee29d60bff68..3b50a2e5b850611dffaa1918be83b188c175ddf0 100644 --- a/src/operation/iPA/test/PowerTest.cc +++ b/src/operation/iPA/test/PowerTest.cc @@ -104,82 +104,12 @@ TEST_F(PowerTest, runIR) { const char* design_work_space = "/home/taosimin/ir_example/aes/rpt"; timing_engine->set_design_work_space(design_work_space); - std::vector lib_files{ - "/home/taosimin/T28/lib/tcbn28hpcplusbwp40p140ssg0p81v125c.lib", - "/home/taosimin/T28/lib/tcbn28hpcplusbwp40p140hvtssg0p81v125c.lib", - "/home/taosimin/T28/lib/tcbn28hpcplusbwp35p140ssg0p81v125c.lib", - "/home/taosimin/T28/lib/tcbn28hpcplusbwp35p140lvtssg0p81v125c.lib", - "/home/taosimin/T28/lib/tcbn28hpcplusbwp40p140lvtssg0p81v125c.lib", - "/home/taosimin/T28/lib/tcbn28hpcplusbwp30p140lvtssg0p81v125c.lib", - "/home/taosimin/T28/lib/tcbn28hpcplusbwp30p140ssg0p81v125c.lib"}; + std::vector lib_files{}; timing_engine->readLiberty(lib_files); timing_engine->get_ista()->set_analysis_mode(ista::AnalysisMode::kMaxMin); - std::vector lef_files{ - "/home/taosimin/T28/tlef/tsmcn28_9lm6X2ZUTRDL.tlef", - "/home/taosimin/T28/lef/PLLTS28HPMLAINT.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140opplvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140lvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140uhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140hvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140oppuhvt.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta256x32m4fw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140cg.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140oppuhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140mbhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140ulvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140uhvt.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta64x100m2fw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140hvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140oppulvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140mb.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140cgcwhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140lvt.lef", - "/home/taosimin/T28/lef/tpbn28v_9lm.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta64x128m2f_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140uhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140mblvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140cgcw.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140mbhvt.lef", - "/home/taosimin/T28/lef/tpbn28v.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta64x128m2fw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140lvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140ulvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140opphvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140cgehvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140mb.lef", - "/home/taosimin/T28/lef/tphn28hpcpgv18_9lm.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta64x88m2fw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140mb.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140cghvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140opp.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140cghvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140oppehvt.lef", - "/home/taosimin/T28/lef/ts1n28hpcplvtb2048x48m8sw_180a.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta64x92m2fw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140mblvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140cg.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140opplvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140cg.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140opphvt.lef", - "/home/taosimin/T28/lef/ts1n28hpcplvtb512x128m4sw_180a.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta64x96m2fw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140opphvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140hvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140oppuhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140cguhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140opp.lef", - "/home/taosimin/T28/lef/ts1n28hpcplvtb512x64m4sw_180a.lef", - "/home/taosimin/T28/lef/ts6n28hpcplvta2048x32m8sw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140opp.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140oppulvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140ehvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140opplvt.lef", - "/home/taosimin/T28/lef/ts1n28hpcplvtb8192x64m8sw_180a.lef"}; + std::vector lef_files{}; std::string def_file = "/home/taosimin/ir_example/aes/aes.def"; timing_engine->readDefDesign(def_file, lef_files); @@ -197,7 +127,7 @@ TEST_F(PowerTest, runIR) { Power* ipower = Power::getOrCreatePower(&(ista->get_graph())); ipower->runCompleteFlow(); - + std::string power_net_name = "VDD"; ipower->runIRAnalysis(power_net_name); } @@ -210,83 +140,13 @@ TEST_F(PowerTest, estimateIR) { const char* design_work_space = "/home/taosimin/ir_example/aes/rpt"; timing_engine->set_design_work_space(design_work_space); - std::vector lib_files{ - "/home/taosimin/T28/lib/tcbn28hpcplusbwp40p140ssg0p81v125c.lib", - "/home/taosimin/T28/lib/tcbn28hpcplusbwp40p140hvtssg0p81v125c.lib", - "/home/taosimin/T28/lib/tcbn28hpcplusbwp35p140ssg0p81v125c.lib", - "/home/taosimin/T28/lib/tcbn28hpcplusbwp35p140lvtssg0p81v125c.lib", - "/home/taosimin/T28/lib/tcbn28hpcplusbwp40p140lvtssg0p81v125c.lib", - "/home/taosimin/T28/lib/tcbn28hpcplusbwp30p140lvtssg0p81v125c.lib", - "/home/taosimin/T28/lib/tcbn28hpcplusbwp30p140ssg0p81v125c.lib"}; + std::vector lib_files{}; timing_engine->readLiberty(lib_files); timing_engine->get_ista()->set_analysis_mode(ista::AnalysisMode::kMaxMin); timing_engine->get_ista()->set_n_worst_path_per_clock(1); - std::vector lef_files{ - "/home/taosimin/T28/tlef/tsmcn28_9lm6X2ZUTRDL.tlef", - "/home/taosimin/T28/lef/PLLTS28HPMLAINT.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140opplvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140lvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140uhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140hvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140oppuhvt.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta256x32m4fw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140cg.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140oppuhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140mbhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140ulvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140uhvt.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta64x100m2fw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140hvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140oppulvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140mb.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140cgcwhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140lvt.lef", - "/home/taosimin/T28/lef/tpbn28v_9lm.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta64x128m2f_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140uhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140mblvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140cgcw.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140mbhvt.lef", - "/home/taosimin/T28/lef/tpbn28v.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta64x128m2fw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140lvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140ulvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140opphvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140cgehvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140mb.lef", - "/home/taosimin/T28/lef/tphn28hpcpgv18_9lm.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta64x88m2fw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140mb.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140cghvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140opp.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140cghvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140oppehvt.lef", - "/home/taosimin/T28/lef/ts1n28hpcplvtb2048x48m8sw_180a.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta64x92m2fw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140mblvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140cg.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140opplvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140cg.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140opphvt.lef", - "/home/taosimin/T28/lef/ts1n28hpcplvtb512x128m4sw_180a.lef", - "/home/taosimin/T28/lef/ts5n28hpcplvta64x96m2fw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140opphvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140hvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140oppuhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140cguhvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140opp.lef", - "/home/taosimin/T28/lef/ts1n28hpcplvtb512x64m4sw_180a.lef", - "/home/taosimin/T28/lef/ts6n28hpcplvta2048x32m8sw_130a.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp30p140opp.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp35p140oppulvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140ehvt.lef", - "/home/taosimin/T28/lef/tcbn28hpcplusbwp40p140opplvt.lef", - "/home/taosimin/T28/lef/ts1n28hpcplvtb8192x64m8sw_180a.lef"}; + std::vector lef_files{}; std::string def_file = "/home/taosimin/ir_example/aes/aes.def"; timing_engine->readDefDesign(def_file, lef_files); @@ -313,7 +173,8 @@ TEST_F(PowerTest, estimateIR) { // power_engine->buildPGNetWireTopo(); // or read pg spef to calc rc. - const char* pg_spef_file_path = "/home/taosimin/ir_example/aes/aes_vdd_vss.spef"; + const char* pg_spef_file_path = + "/home/taosimin/ir_example/aes/aes_vdd_vss.spef"; power_engine->readPGSpef(pg_spef_file_path); power_engine->runIRAnalysis(power_net_name); diff --git a/src/operation/iPDN/api/ipdn_api.cpp b/src/operation/iPDN/api/ipdn_api.cpp index 4f4517b1fee0d33866681e373351d6fb1b820605..3f944421896d5fcab25aafc46af57d6b33487e6d 100644 --- a/src/operation/iPDN/api/ipdn_api.cpp +++ b/src/operation/iPDN/api/ipdn_api.cpp @@ -29,14 +29,14 @@ void PdnApi::addIOPin(std::string pin_name, std::string net_name, std::string di { PdnPlan pdn_plan; - return pdn_plan.addIOPin(pin_name, net_name, direction, is_power); + pdn_plan.addIOPin(pin_name, net_name, direction, is_power); } void PdnApi::globalConnect(const std::string pdn_net_name, const std::string instance_pdn_pin_name, bool is_power) { PdnPlan pdn_plan; - return pdn_plan.globalConnect(pdn_net_name, instance_pdn_pin_name, is_power); + pdn_plan.globalConnect(pdn_net_name, instance_pdn_pin_name, is_power); } void PdnApi::placePdnPort(std::string pin_name, std::string io_cell_name, int32_t offset_x, int32_t offset_y, int32_t width, int32_t height, @@ -44,7 +44,7 @@ void PdnApi::placePdnPort(std::string pin_name, std::string io_cell_name, int32_ { PdnPlan pdn_plan; - return pdn_plan.placePdnPort(pin_name, io_cell_name, offset_x, offset_y, width, height, layer_name); + pdn_plan.placePdnPort(pin_name, io_cell_name, offset_x, offset_y, width, height, layer_name); } void PdnApi::createGrid(std::string power_net_name, std::string ground_net_name, std::string layer_name, double route_width, @@ -52,7 +52,7 @@ void PdnApi::createGrid(std::string power_net_name, std::string ground_net_name, { PdnPlan pdn_plan; - return pdn_plan.createGrid(power_net_name, ground_net_name, layer_name, route_width, route_offset); + pdn_plan.createGrid(power_net_name, ground_net_name, layer_name, route_width, route_offset); } /** * @brief 创建电源网络 @@ -69,7 +69,7 @@ void PdnApi::createStripe(std::string power_net_name, std::string ground_net_nam { PdnPlan pdn_plan; - return pdn_plan.createStripe(power_net_name, ground_net_name, layer_name, route_width, pitchh, route_offset); + pdn_plan.createStripe(power_net_name, ground_net_name, layer_name, route_width, pitchh, route_offset); } void PdnApi::connectLayerList(std::vector& layer_list) @@ -96,21 +96,21 @@ void PdnApi::connectMacroToPdnGrid(std::vector power_name, std::vec { PdnPlan pdn_plan; - return pdn_plan.connectMacroToPdnGrid(power_name, ground_name, layer_name_first, layer_name_second, orient); + pdn_plan.connectMacroToPdnGrid(power_name, ground_name, layer_name_first, layer_name_second, orient); } void PdnApi::connectIOPinToPowerStripe(std::vector& point_list, const std::string layer_name) { PdnPlan pdn_plan; - return pdn_plan.connectIOPinToPowerStripe(point_list, layer_name); + pdn_plan.connectIOPinToPowerStripe(point_list, layer_name); } void PdnApi::connectPowerStripe(std::vector& point_list, const std::string& net_name, const std::string& layer_name, int32_t width) { PdnPlan pdn_plan; - return pdn_plan.connectPowerStripe(point_list, net_name, layer_name, width); + pdn_plan.connectPowerStripe(point_list, net_name, layer_name, width); } bool PdnApi::addSegmentStripeList(std::vector& point_list, std::string net_name, std::string layer_name, int32_t width) diff --git a/src/operation/iPL/README.md b/src/operation/iPL/README.md index c41a3194b595d72867a085d59117986ae2a741c6..561bcd824949f49c0a55a862645cd47ae6c6e535 100644 --- a/src/operation/iPL/README.md +++ b/src/operation/iPL/README.md @@ -1,92 +1,275 @@ -# iPL用户指南 +# iPL: Placement -> ## iPL简介 +## 1. Background Introduction -### 软件结构图 +1. Placement Problem: Given a set of cells with connection relationships (nets) and a placement area, the placement places the cells. The general placement goal is to minimize the total wire length/timing/power consumption of the nets, and requires the cells to meet the legality requirements (within the placement area, aligned with Rows/Sites, and no overlap between cells, etc.). -
+ - Net: A single net can connect multiple Pin points (Pin points are located on the cells or at the IO); The routing direction of the net is only horizontal and vertical. + - Cell: The shape is usually rectangular. Cell types include macro cells, standard cells (timing cells, logic cells), etc.; Cell states include fixed and to be placed. +
iPL-logo - **iPL--一款面向流片需求,支持合法摆放M1层单元的自动布局器** +Figure 1 Main Flowchart of iPL +
-
-### 支持功能 +## 2. Main Implementations -- 支持标准单元的全局布局、合法化、详细布局; -- 支持对布局结果进行违例检查、报告布局阶段线长、密度、时序、拥塞 -- 支持在布局阶段插入buffer进行长线优化; -- 支持增量式合法化; -- 时序优化与拥塞优化进一步完善中; +### 2.1 Function Implementations + + + +Figure 5 The main placement process implemented in iPL. Solving large-scale placement problems in one step is NP-hard. Therefore, it is generally divided into three stages: global placement, legalization, and detailed placement. + + - Place std cell into proper location + - Satisfy layer poly, well, contact, and metal 1 design rule + - Optimize wirelength, timing, congestion + - Place macro cell location automatically + - Incremental placement + - Timing-driven placement (coming soon) + - Congestion-driven placement (coming soon) + + + +Figure 6 Schematic Diagram of Placement + +### 2.2 Tool API Implementations + +| Method Name | Sub-method | Type | Parameter List | Return Value | Method Description | +| :------------------- | :-------------------------------- | :-------- | :------------------------- | :------------- | :--------------------------- | +| initAPI | * | action | pl_json_path, idb_builder | self | Initialize iPL | +| runFlow | runGP | action | void | self | Run global placement | +| runFlow | runBufferInsertion | action | void | self | Run buffer insertion | +| runFlow | runLG | action | void | self | Run legalization | +| runFlow | runDP | action | void | self | Run detailed placement | +| runFlow | writeBackSourceDataBase | action | void | self | Write back placement data to the data source | +| runIncrLG | * | action | inst_list | self | Run incremental legalization | +| updatePlacerDB | * | action | void/inst_list | self | Update (specified) data from the data source | +| obtainAvailableWhiteSpaceList | * | action | row_range, site_range | rectanglelist | Obtain the available placement space in the specified area (for inserting cells) | +| checkLegality | * | accessor | void | bool | Check the legality of the current placement result | +| isSTAStarted | * | accessor | void | bool | Check if STA has been started | +| isPlacerDBStarted | * | accessor | void | bool | Check if PlacerDB has been initialized | +| isAbucasLGStarted | * | accessor | void | bool | Check if the Abucas legalizer has been started | +| reportPLInfo | reportHPWLInfo | accessor | feed | self | Report HPWL information | +| reportPLInfo | reportSTWLInfo | accessor | feed | self | Report STWL information | +| reportPLInfo | reportLongNetInfo | accessor | feed | self | Report long net information | +| reportPLInfo | reportLayoutInfo | accessor | feed | self | Report layout violation information | +| reportPLInfo | reportPeakBinDensity | accessor | feed | self | Report the peak density of the Bin area | +| reportPLInfo | reportTimingInfo | accessor | feed | self | Report layout timing information | +| reportPLInfo | reportCongestionInfo | accessor | feed | self | Report layout congestion information | +| obtainTimingInfo | obtainPinEarly(Late)Slack | action | pin_name | value | Obtain the Slack information on the Pin | +| obtainTimingInfo | obtainPinEarly(Late)ArrivalTime | action | pin_name | value | Obtain the ArrivalTime information on the Pin | +| obtainTimingInfo | obtainPinEarly(Late)RequiredTime | action | pin_name | value | Obtain the RequiredTime information on the Pin | +| obtainTimingInfo | obtainWNS/TNS | action | clk_name | value | Obtain WNS/TNS information | +| obtainTimingInfo | updateTiming | action | void | self | Update timing evaluation | +| obtainCongesionInfo | obtainPinDens | action | void | value | Obtain Pin Density information | +| obtainCongesionInfo | obtainNetCong | action | rudy_type | value | Obtain net congestion information | +| obtainCongesionInfo | evalGRCong | action | void | value | Update congestion evaluation | + +## 3. Key Technologies + +### 3.1 Module Design + + + +Figure 7 Division of iPL Modules + + - PlacerDB Module: Encapsulates and maintains the layout data (layout) and design data (Design) required for placement + - Operator Module: Extracts placement data for operation, calls the solver module for solving during the process, the evaluator module for evaluating indicators, and the checker module for checking the placement result + - Solver Module: A collection of mature solving tools to assist in placement + - Checker Module: Conduct violation checks, functional detections, and report output on the current placement. Evaluator Module: Evaluate the current placement indicators + - Wrapper Module: Read placement data from the data source and write the placement result back to the data source + - API: The interaction interface between iPL and the outside + +### 3.2 Routing Feasibility Solution + + - Wirelength Gradient: WA Wirelength Smooth Model + - Density Gradient: e-Density Electrostatic Field Model + - Optimization Algorithm: Nesterov Gradient Descent Algorithm + - Congestion Evaluation Method (API provided by iEDA evaluator): + - LUT-RUDY (Look Up Table-based RUDY) + - Early-GR + - Fine-grained Cell Expansion: + - Select cells in peak congestion grids for expansion + - Independent expansion in H/V directions + - Dynamic expansion rate adjustment + - Superlinear expansion index correction + +When all cells in the global placement are spread out enough (density overflow < 0.2), start evaluating and optimizing the routing feasibility. + + + +Figure 8 Process of iPL Routing Feasibility Solution + +## 4. Input and Output + +**Input** + + - Netlist optimization def file./result/iTO_fix_fanout_result.def + +**Output** + + -./result/iPL_result.def + -./result/iPL_result.v + +**Evaluation and Report** + + -./result/report/pl_db.rpt + +The intermediate reports of the iPL tool are stored in the directory by default: `./scripts/design/sky130_gcd/result/pl/` + + + +Figure 9 Checking whether the current placement result has violations. The detailed violation situation is in the file violation_record.txt in the same-level directory + + + +Figure 10 Wire length index report of placement optimization. The detailed report of long nets is in the file wirelength_record.txt in the same-level directory; The density information of cell distribution, the detailed report is in the file density_record.txt in the same-level directory; The timing information of the placement result, the detailed report is in the file timing_record.txt in the same-level directory; The routing feasibility information of the placement result, the detailed report is in the file congestion_record.txt in the same-level directory + + - report/violation_record.txt : Cells with placement violations + - report/wirelength_record.txt : Statistics of HPWL wire length, STWL wire length, and long wire length of the placement + - report/density_record.txt : Peak bin density of the placement + - report/timing_record.txt : Timing information of the placement (wns, tns), calling Flute for simple routing + - report/congestion_record.txt : Routing feasibility information of the placement + +## 5 **Parameter Description** + +Refer to iEDA_config/pl_default_config.json: `./scripts/design/sky130_gcd/iEDA_config/pl_default_config.json` + +| Parameter Name | Function Description | Parameter Range | Default Value | +| :--------------------------------------------- | :----------------------------------------------------------- | :---------------------------- | :------------- | +| is_max_length_opt | Whether to enable maximum wire length optimization | [0,1] | 0 | +| max_length_constraint | Specify the maximum wire length | [0-1000000] | 1000000 | +| is_timing_aware_mode | Whether to enable timing mode | [0,1] | 0 | +| ignore_net_degree | Ignore nets with more than the specified number of pins | [10-10000] | 100 | +| num_threads | Specify the number of CPU threads | [1-64] | 8 | +| [GP-Wirelength] init_wirelength_coef | Set the initial wire length coefficient | [0.0-1.0] | 0.25 | +| [GP-Wirelength] reference_hpwl | Adjust the reference wire length for density penalty | [100-1000000] | 446000000 | +| [GP-Wirelength] min_wirelength_force_bar | Control the wire length boundary | [-1000-0] | -300 | +| [GP-Density] target_density | Specify the target density | [0.0-1.0] | 0.8 | +| [GP-Density] bin_cnt_x | Specify the number of Bins in the horizontal direction | [16,32,64,128,256,512,1024] | 512 | +| [GP-Density] bin_cnt_y | Specify the number of Bins in the vertical direction | [16,32,64,128,256,512,1024] | 512 | +| [GP-Nesterov] max_iter | Specify the maximum number of iterations | [50-2000] | 2000 | +| [GP-Nesterov] max_backtrack | Specify the maximum number of backtracks | [0-100] | 10 | +| [GP-Nesterov] init_density_penalty | Specify the density penalty in the initial state | [0.0-1.0] | 0.00008 | +| [GP-Nesterov] target_overflow | Specify the target overflow value | [0.0-1.0] | 0.1 | +| [GP-Nesterov] initial_prev_coordi_update_coef | The coefficient when perturbing the initial coordinates | [10-10000] | 100 | +| [GP-Nesterov] min_precondition | Set the minimum value of the precondition | [1-100] | 1 | +| [GP-Nesterov] min_phi_coef | Set the minimum phi parameter | [0.0-1.0] | 0.95 | +| [GP-Nesterov] max_phi_coef | Set the maximum phi parameter | [0.0-1.0] | 1.05 | +| [BUFFER] max_buffer_num | Specify the maximum number of buffers to be inserted | [0-1000000] | 35000 | +| [BUFFER] buffer_type | Specify the name of the buffer type that can be inserted | Process-related | List[...,...] | +| [LG] max_displacement | Specify the maximum displacement of cells | [10000-1000000] | 50000 | +| [LG] global_right_padding | Specify the spacing between cells (in units of Site) | [0,1,2,3,4...] | 1 | +| [DP] max_displacement | Specify the maximum displacement of cells | [10000-1000000] | 50000 | +| [DP] global_right_padding | Specify the spacing between cells (in units of Site) | [0,1,2,3,4...] | 1 | +| [Filler] first_iter | Specify the Filler used in the first iteration | Process-related | List[...,...] | +| [Filler] second_iter | Specify the Filler used in the second iteration | Process-related | List[...,...] | +| [Filler] min_filler_width | Specify the minimum width of the Filler (in units of Site) | Process-related | 1 | +| [MP] fixed_macro | Specify the fixed macro unit (string macro_name) | Design-related | List[...,...] | +| [MP] fixed_macro_coordinate | Specify the position coordinates of the fixed macro unit (int location_x, int location_y) | Design-related | List[...,...] | +| [MP] blockage | Specify the rectangular blocking area of the macro unit, and the macro unit should avoid being placed in this area (int left_bottom_x, int left_bottom_y, int right_top_x, int right_top_y) | Design-related | List[...,...] | +| [MP] guidance_macro | Specify the macro unit for guidance placement, and each macro unit can set the expected placement area (string macro_name) | Design-related | List[...,...] | +| [MP] guidance | Specify the guidance placement area corresponding to the macro unit (int left_bottom_x, int left_bottom_y, int right_top_x, int right_top_y) | Design-related | List[...,...] | +| [MP] solution_type | Specify the representation of the solution | ["BStarTree","SequencePair"] | "BStarTree" | +| [MP] perturb_per_step | Specify the number of perturbations per step in the simulated annealing | [10-1000] | 100 | +| [MP] cool_rate | Specify the cooling rate of the simulated annealing temperature | [0.0-1.0] | 0.92 | +| [MP] parts | Specify the number of partitions of standard cells (int) | [10-100] | 66 | +| [MP] ufactor | Specify the unbalance value of the standard cell partition (int) | [10-1000] | 100 | +| [MP] new_macro_density | Specify the density of the virtual macro unit | [0.0-1.0] | 0.6 | +| [MP] halo_x | Specify the halo in the horizontal direction of the macro unit | [0-1000000] | 0 | +| [MP] halo_y | Specify the halo in the vertical direction of the macro unit | [0-1000000] | 0 | +| [MP] output_path | Specify the output file path | | "./result/pl" | + + +### Supported Functions + + - Support global placement, legalization, and detailed placement of standard cells; + - Support conducting violation checks on the placement result, reporting wire length, density, timing, and congestion in the placement stage + - Support inserting buffers during the placement stage for long wire optimization; + - Support incremental legalization; + - Timing optimization and congestion optimization are further improved; --- -> ## iPL使用示例 +> ## iPL Usage Example -### 通过tcl启动 +### Startup via tcl -参考iPL_script/run_iPL.tcl: `/scripts/design/sky130_gcd/script/iPL_script/run_iPL.tcl` +Refer to iPL_script/run_iPL.tcl: `/scripts/design/sky130_gcd/script/iPL_script/run_iPL.tcl` -iPL支持使用的tcl命令 +Tcl commands supported by iPL ``` -run_placer -conifg // 完整运行整个iPL -run_filler -conifg // 对布局的空白区域进行单元填充 -run_incremental_flow -conifg // 对改变单元位置的结果进行重新合法化 -run_incremental_lg // 进行增量式合法化,需保证iPL已运行 -placer_check_legality // 检查当前布局的合法性 -placer_report // 对当前布局的状态进行report -init_pl -conifg // 对布局器进行初始化 -destroy_pl // 销毁布局器 -placer_run_mp // 进行宏单元布局 -placer_run_gp // 进行标准单元全局布局 -placer_run_lg // 进行标准单元合法化 -placer_run_dp // 进行标准单元详细布局 +run_placer -conifg // Run the entire iPL completely +run_filler -conifg // Fill the blank areas of the placement with cells +run_incremental_flow -conifg // Re-legalize the result of changing the cell positions +run_incremental_lg // Perform incremental legalization. Ensure iPL has been run +placer_check_legality // Check the legality of the current placement +placer_report // Report the status of the current placement +init_pl -conifg // Initialize the placer +destroy_pl // Destroy the placer +placer_run_mp // Perform macro cell placement +placer_run_gp // Perform global placement of standard cells +placer_run_lg // Perform legalization of standard cells +placer_run_dp // Perform detailed placement of standard cells ``` -### Config配置文件 - -参考iEDA_config/pl_default_config.json: `/scripts/design/sky130_gcd/iEDA_config/pl_default_config.json` - -| JSON参数 | 功能说明 | 参数范围 | 默认值 | -| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | ------------- | -| is_max_length_opt | 是否开启最大线长优化 | [0,1] | 0 | -| max_length_constraint | 指定最大线长 | [0-1000000] | 1000000 | -| is_timing_effort | 是否开启时序优化模式 | [0,1] | 0 | -| is_congestion_effort | 是否开启可布线性优化模式 | | | -| ignore_net_degree | 忽略超过指定pin个数的线网 | [10-10000] | 100 | -| num_threads | 指定的CPU线程数 | [1-64] | 8 | -| [GP-Wirelength] init_wirelength_coef | 设置初始线长系数 | [0.0-1.0] | 0.25 | -| [GP-Wirelength] reference_hpwl | 调整密度惩罚的参考线长 | [100-1000000] | 446000000 | -| [GP-Wirelength] min_wirelength_force_bar | 控制线长边界 | [-1000-0] | -300 | -| [GP-Density] target_density | 指定的目标密度 | [0.0-1.0] | 0.8 | -| [GP-Density] bin_cnt_x | 指定水平方向上Bin的个数 | [16,32,64,128,256,512,1024] | 512 | -| [GP-Density] bin_cnt_y | 指定垂直方向上Bin的个数 | [16,32,64,128,256,512,1024] | 512 | -| [GP-Nesterov] max_iter | 指定最大的迭代次数 | [50-2000] | 2000 | -| [GP-Nesterov] max_backtrack | 指定最大的回溯次数 | [0-100] | 10 | -| [GP-Nesterov] init_density_penalty | 指定初始状态的密度惩罚 | [0.0-1.0] | 0.00008 | -| [GP-Nesterov] target_overflow | 指定目标的溢出值 | [0.0-1.0] | 0.1 | -| [GP-Nesterov] initial_prev_coordi_update_coef | 初始扰动坐标时的系数 | [10-10000] | 100 | -| [GP-Nesterov] min_precondition | 设置precondition的最小值 | [1-100] | 1 | -| [GP-Nesterov] min_phi_coef | 设置最小的phi参数 | [0.0-1.0] | 0.95 | -| [GP-Nesterov] max_phi_coef | 设置最大的phi参数 | [0.0-1.0] | 1.05 | -| [BUFFER] max_buffer_num | 指定限制最大buffer插入个数 | [0-1000000] | 35000 | -| [BUFFER] buffer_type | 指定可插入的buffer类型名字 | 工艺相关 | 列表[...,...] | -| [LG] max_displacement | 指定单元的最大移动量 | [10000-1000000] | 50000 | -| [LG] global_right_padding | 指定单元间的间距(以Site为单位) | [0,1,2,3,4...] | 1 | -| [DP] max_displacement | 指定单元的最大移动量 | [10000-1000000] | 50000 | -| [DP] global_right_padding | 指定单元间的间距(以Site为单位) | [0,1,2,3,4...] | 1 | -| [Filler] first_iter | 指定第一轮迭代使用的Filler | 工艺相关 | 列表[...,...] | -| [Filler] second_iter | 指定第二轮迭代使用的Filler | 工艺相关 | 列表[...,...] | -| [Filler] min_filler_width | 指定Filler的最小宽度(以Site为单位) | 工艺相关 | 1 | - - -### 运行的Log、Report - -默认存放在目录:`/scripts/design/sky130_gcd/result/pl/` - -* report/violation_record.txt :布局违例的单元 -* report/wirelength_record.txt :布局的HPWL线长、STWL线长以及长线线长统计 -* report/density_record.txt :布局的峰值bin密度 -* report/timing_record.txt :布局的时序信息(wns、tns),调用Flute进行简易绕线 +### Config Configuration File + +Refer to iEDA_config/pl_default_config.json: `/scripts/design/sky130_gcd/iEDA_config/pl_default_config.json` + +| JSON Parameter | Function Description | Parameter Range | Default Value | +| :--------------------------------------------- | :----------------------------------------------------------- | :---------------------------- | :------------- | +| is_max_length_opt | Whether to enable maximum wire length optimization | [0,1] | 0 | +| max_length_constraint | Specify the maximum wire length | [0-1000000] | 1000000 | +| is_timing_effort | Whether to enable timing optimization mode | [0,1] | 0 | +| is_congestion_effort | Whether to enable routability optimization mode | | | +| ignore_net_degree | Ignore nets with more than the specified number of pins | [10-10000] | 100 | +| num_threads | Specify the number of CPU threads | [1-64] | 8 | +| [GP-Wirelength] init_wirelength_coef | Set the initial wire length coefficient | [0.0 - 1.0] | 0.25 | +| [GP-Wirelength] reference_hpwl | Adjust the reference wire length for density penalty | [100 - 1000000] | 446000000 | +| [GP-Wirelength] min_wirelength_force_bar | Control the wire length boundary | [-1000 - 0] | -300 | +| [GP-Density] target_density | Specify the target density | [0.0 - 1.0] | 0.8 | +| [GP-Density] bin_cnt_x | Specify the number of Bins in the horizontal direction | [16, 32, 64, 128, 256, 512, 1024] | 512 | +| [GP-Density] bin_cnt_y | Specify the number of Bins in the vertical direction | [16, 32, 64, 128, 256, 512, 1024] | 512 | +| [GP-Nesterov] max_iter | Specify the maximum number of iterations | [50 - 2000] | 2000 | +| [GP-Nesterov] max_backtrack | Specify the maximum number of backtracks | [0 - 100] | 10 | +| [GP-Nesterov] init_density_penalty | Specify the density penalty in the initial state | [0.0 - 1.0] | 0.00008 | +| [GP-Nesterov] target_overflow | Specify the target overflow value | [0.0 - 1.0] | 0.1 | +| [GP-Nesterov] initial_prev_coordi_update_coef | The coefficient when perturbing the initial coordinates | [10 - 10000] | 100 | +| [GP-Nesterov] min_precondition | Set the minimum value of the precondition | [1 - 100] | 1 | +| [GP-Nesterov] min_phi_coef | Set the minimum phi parameter | [0.0 - 1.0] | 0.95 | +| [GP-Nesterov] max_phi_coef | Set the maximum phi parameter | [0.0 - 1.0] | 1.05 | +| [BUFFER] max_buffer_num | Specify the maximum number of buffers to be inserted | [0 - 1000000] | 35000 | +| [BUFFER] buffer_type | Specify the name of the buffer type that can be inserted | Process-related | List[...,...] | +| [LG] max_displacement | Specify the maximum displacement of cells | [10000 - 1000000] | 50000 | +| [LG] global_right_padding | Specify the spacing between cells (in units of Site) | [0, 1, 2, 3, 4,...] | 1 | +| [DP] max_displacement | Specify the maximum displacement of cells | [10000 - 1000000] | 50000 | +| [DP] global_right_padding | Specify the spacing between cells (in units of Site) | [0, 1, 2, 3, 4,...] | 1 | +| [Filler] first_iter | Specify the Filler used in the first iteration | Process-related | List[...,...] | +| [Filler] second_iter | Specify the Filler used in the second iteration | Process-related | List[...,...] | +| [Filler] min_filler_width | Specify the minimum width of the Filler (in units of Site) | Process-related | 1 | +| [MP] fixed_macro | Specify the fixed macro unit (string macro_name) | Design-related | List[...,...] | +| [MP] fixed_macro_coordinate | Specify the position coordinates of the fixed macro unit (int location_x, int location_y) | Design-related | List[...,...] | +| [MP] blockage | Specify the rectangular blocking area of the macro unit, and the macro unit should avoid being placed in this area (int left_bottom_x, int left_bottom_y, int right_top_x, int right_top_y) | Design-related | List[...,...] | +| [MP] guidance_macro | Specify the macro unit for guidance placement, and each macro unit can set the expected placement area (string macro_name) | Design-related | List[...,...] | +| [MP] guidance | Specify the guidance placement area corresponding to the macro unit (int left_bottom_x, int left_bottom_y, int right_top_x, int right_top_y) | Design-related | List[...,...] | +| [MP] solution_type | Specify the representation of the solution | ["BStarTree", "SequencePair"] | "BStarTree" | +| [MP] perturb_per_step | Specify the number of perturbations per step in the simulated annealing | [10 - 1000] | 100 | +| [MP] cool_rate | Specify the cooling rate of the simulated annealing temperature | [0.0 - 1.0] | 0.92 | +| [MP] parts | Specify the number of partitions of standard cells (int) | [10 - 100] | 66 | +| [MP] ufactor | Specify the unbalance value of the standard cell partition (int) | [10 - 1000] | 100 | +| [MP] new_macro_density | Specify the density of the virtual macro unit | [0.0 - 1.0] | 0.6 | +| [MP] halo_x | Specify the halo in the horizontal direction of the macro unit | [0 - 1000000] | 0 | +| [MP] halo_y | Specify the halo in the vertical direction of the macro unit | [0 - 1000000] | 0 | + +### Running Log and Report + +Stored in the directory by default: `/scripts/design/sky130_gcd/result/pl/` + + * report/violation_record.txt : Cells with placement violations + * report/wirelength_record.txt : Statistics of HPWL wire length, STWL wire length, and long wire length of the placement + * report/density_record.txt : Peak bin density of the placement + * report/timing_record.txt : Timing information of the placement (wns, tns), calling Flute for simple routing \ No newline at end of file diff --git a/src/operation/iPL/api/PLAPI.cc b/src/operation/iPL/api/PLAPI.cc index 420a833db0ef9b2cacf3f62ba3112aa74e231e80..656afec6183ae69fc28acf75b17c5898c9d1c138 100644 --- a/src/operation/iPL/api/PLAPI.cc +++ b/src/operation/iPL/api/PLAPI.cc @@ -176,6 +176,7 @@ void PLAPI::createPLDirectory() void PLAPI::runIncrementalFlow() { runLG(); + notifyPLWLInfo(1); reportPLInfo(); writeBackSourceDataBase(); } @@ -389,7 +390,7 @@ void PLAPI::runFlow() runGP(); // printHPWLInfo(); // printTimingInfo(); - // notifyPLWLInfo(0); + notifyPLWLInfo(0); // if (isSTAStarted()) { // notifyPLCongestionInfo(0); // notifyPLTimingInfo(0); @@ -410,7 +411,7 @@ void PLAPI::runFlow() runLG(); // printHPWLInfo(); // printTimingInfo(); - // notifyPLWLInfo(1); + notifyPLWLInfo(1); // if (isSTAStarted()) { // notifyPLCongestionInfo(1); // notifyPLTimingInfo(1); @@ -425,7 +426,7 @@ void PLAPI::runFlow() // printHPWLInfo(); // printTimingInfo(); - // notifyPLWLInfo(2); + notifyPLWLInfo(2); // if (isSTAStarted()) { // notifyPLCongestionInfo(2); // notifyPLTimingInfo(2); @@ -549,18 +550,18 @@ void PLAPI::runNetworkFlowSpread() void PLAPI::notifyPLWLInfo(int stage) { // 1. origin method - // HPWirelength hpwl(PlacerDBInst.get_topo_manager()); - // SteinerWirelength stwl(PlacerDBInst.get_topo_manager()); - // stwl.updateAllNetWorkPointPair(); - // PlacerDBInst.PL_HPWL[stage] = hpwl.obtainTotalWirelength(); - // PlacerDBInst.PL_STWL[stage] = stwl.obtainTotalWirelength(); + HPWirelength hpwl(PlacerDBInst.get_topo_manager()); + SteinerWirelength stwl(PlacerDBInst.get_topo_manager()); + stwl.updateAllNetWorkPointPair(); + PlacerDBInst.PL_HPWL[stage] = hpwl.obtainTotalWirelength(); + PlacerDBInst.PL_STWL[stage] = stwl.obtainTotalWirelength(); // 2. most work in evalpro - this->writeBackSourceDataBase(); - ieval::TotalWLSummary wl_summary = _external_api->evalproIDBWL(); - PlacerDBInst.PL_HPWL[stage] = wl_summary.HPWL; - PlacerDBInst.PL_STWL[stage] = wl_summary.FLUTE; - PlacerDBInst.PL_GRWL[stage] = wl_summary.GRWL; + // this->writeBackSourceDataBase(); + // ieval::TotalWLSummary wl_summary = _external_api->evalproIDBWL(); + // PlacerDBInst.PL_HPWL[stage] = wl_summary.HPWL; + // PlacerDBInst.PL_STWL[stage] = wl_summary.FLUTE; + // PlacerDBInst.PL_GRWL[stage] = wl_summary.GRWL; } void PLAPI::notifyPLCongestionInfo(int stage) @@ -964,46 +965,18 @@ ieda_feature::PlaceSummary PLAPI::outputSummary(std::string step) // 1:全局布局、详细布局、合法化都需要存储的数据参数,需要根据step存储不同的值 auto place_density = PlacerDBInst.place_density; - // auto pin_density = PlacerDBInst.pin_density; - // auto HPWL = PlacerDBInst.PL_HPWL; - // auto STWL = PlacerDBInst.PL_STWL; - // auto GRWL = PlacerDBInst.PL_GRWL; - - // auto egr_tof = PlacerDBInst.egr_tof; - // auto egr_mof = PlacerDBInst.egr_mof; - // auto egr_ace = PlacerDBInst.egr_ace; - - // auto tns = PlacerDBInst.tns; - // auto wns = PlacerDBInst.wns; - // auto suggest_freq = PlacerDBInst.suggest_freq; + auto hpwl = PlacerDBInst.PL_HPWL; + auto stwl = PlacerDBInst.PL_STWL; // 2:全局布局、详细布局需要存储的数据参数 if (step == "place") { summary.gplace.place_density = place_density[0]; - // summary.gplace.pin_density = pin_density[0]; - // summary.gplace.HPWL = HPWL[0]; - // summary.gplace.STWL = STWL[0]; - // summary.gplace.GRWL = GRWL[0]; - - // summary.gplace.egr_tof = egr_tof[0]; - // summary.gplace.egr_mof = egr_mof[0]; - // summary.gplace.egr_ace = egr_ace[0]; - // summary.gplace.tns = tns[0]; - // summary.gplace.wns = wns[0]; - // summary.gplace.suggest_freq = suggest_freq[0]; - - summary.dplace.place_density = place_density[1]; - // summary.dplace.pin_density = pin_density[1]; - // summary.dplace.HPWL = HPWL[1]; - // summary.dplace.STWL = STWL[1]; - // summary.dplace.GRWL = GRWL[1]; - - // summary.dplace.egr_tof = egr_tof[1]; - // summary.dplace.egr_mof = egr_mof[1]; - // summary.dplace.egr_ace = egr_ace[1]; - // summary.dplace.tns = tns[1]; - // summary.dplace.wns = wns[1]; - // summary.dplace.suggest_freq = suggest_freq[1]; + summary.gplace.HPWL = hpwl[0]; + summary.gplace.STWL = stwl[0]; + + summary.dplace.place_density = place_density[2]; + summary.dplace.HPWL = hpwl[2]; + summary.dplace.STWL = stwl[2]; auto* pl_design = PlacerDBInst.get_design(); summary.instance_cnt = pl_design->get_instances_range(); @@ -1027,18 +1000,8 @@ ieda_feature::PlaceSummary PLAPI::outputSummary(std::string step) } // 3:合法化需要存储的数据参数 else if (step == "legalization") { - summary.lg_summary.pl_common_summary.place_density = place_density[2]; - // summary.lg_summary.pl_common_summary.pin_density = pin_density[2]; - // summary.lg_summary.pl_common_summary.HPWL = HPWL[2]; - // summary.lg_summary.pl_common_summary.STWL = STWL[2]; - // summary.lg_summary.pl_common_summary.GRWL = GRWL[2]; - - // summary.lg_summary.pl_common_summary.egr_tof = egr_tof[2]; - // summary.lg_summary.pl_common_summary.egr_mof = egr_mof[2]; - // summary.lg_summary.pl_common_summary.egr_ace = egr_ace[2]; - // summary.lg_summary.pl_common_summary.tns = tns[2]; - // summary.lg_summary.pl_common_summary.wns = wns[2]; - // summary.lg_summary.pl_common_summary.suggest_freq = suggest_freq[2]; + summary.lg_summary.pl_common_summary.HPWL = hpwl[1]; + summary.lg_summary.pl_common_summary.STWL = stwl[1]; summary.lg_summary.lg_total_movement = PlacerDBInst.lg_total_movement; summary.lg_summary.lg_max_movement = PlacerDBInst.lg_max_movement; diff --git a/src/operation/iPL/source/module/evaluator/wirelength/WAWirelengthGradient.cc b/src/operation/iPL/source/module/evaluator/wirelength/WAWirelengthGradient.cc index 08975d4e15695f8a04b9a9c1eef009d51698d5a5..51fcae5d3ce7bb90e3984281c1105be89c57d837 100644 --- a/src/operation/iPL/source/module/evaluator/wirelength/WAWirelengthGradient.cc +++ b/src/operation/iPL/source/module/evaluator/wirelength/WAWirelengthGradient.cc @@ -228,8 +228,7 @@ void WAWirelengthGradient::updateWirelengthForce(float coeff_x, float coeff_y, f void WAWirelengthGradient::updateWirelengthForceDirect(float coeff_x, float coeff_y, float min_force_bar, int32_t thread_num, GridManager* grid_manager) { float util_max = std::max(grid_manager->get_h_util_max(), grid_manager->get_v_util_max()); - // LOG_INFO << "H_UTIL_MAX = " << grid_manager->get_h_util_max() << "; v_UTIL_MAX = " << grid_manager->get_v_util_max(); - // LOG_INFO << "H_UTIL_SUM = " << grid_manager->get_h_util_sum() << "; v_UTIL_SUM = " << grid_manager->get_v_util_sum(); + LOG_INFO << "Congestion Utilizaiton: horizontal_max = " << grid_manager->get_h_util_max() << ", vertical_max = " << grid_manager->get_v_util_max(); // NOLINTNEXTLINE int32_t net_chunk_size = std::max(int(_topology_manager->get_network_list().size() / thread_num / 16), 1); diff --git a/src/operation/iPL/source/module/global_placer/electrostatic_placer/NesterovPlace.cc b/src/operation/iPL/source/module/global_placer/electrostatic_placer/NesterovPlace.cc index f783536cb4d3a0398969086d28258f3a72505f13..6791fe7099526d64fe3edca8c0c5343717c4f7d9 100644 --- a/src/operation/iPL/source/module/global_placer/electrostatic_placer/NesterovPlace.cc +++ b/src/operation/iPL/source/module/global_placer/electrostatic_placer/NesterovPlace.cc @@ -23,26 +23,24 @@ * @FilePath: /irefactor/src/operation/iPL/source/module/global_placer/electrostatic_placer/NesterovPlace.cc * Contact : https://github.com/sjchanson */ -#include -#include - #include "NesterovPlace.hh" #include #include +#include +#include #include #include #include #include "Log.hh" +#include "PLAPI.hh" #include "ipl_io.h" +#include "json/json.hpp" #include "omp.h" #include "tool_manager.h" #include "usage/usage.hh" -#include "PLAPI.hh" -#include "json/json.hpp" - #ifdef BUILD_QT #include "utility/Image.hh" @@ -61,2146 +59,2108 @@ namespace ipl { #define SQRT2 1.414213562373095048801L - void NesterovPlace::initNesConfig(Config* config) - { - _nes_config = config->get_nes_config(); +void NesterovPlace::initNesConfig(Config* config) +{ + _nes_config = config->get_nes_config(); - if (_nes_config.isOptMaxWirelength() || _nes_config.isOptTiming()) { - _nes_config.add_opt_target_overflow(0.15); - _nes_config.add_opt_target_overflow(0.20); - _nes_config.add_opt_target_overflow(0.25); - _nes_config.add_opt_target_overflow(0.30); - } + if (_nes_config.isOptMaxWirelength() || _nes_config.isOptTiming()) { + _nes_config.add_opt_target_overflow(0.15); + _nes_config.add_opt_target_overflow(0.20); + _nes_config.add_opt_target_overflow(0.25); + _nes_config.add_opt_target_overflow(0.30); } +} - void NesterovPlace::initNesDatabase(PlacerDB* placer_db) - { - _nes_database = new NesterovDatabase(); - _nes_database->_placer_db = placer_db; +void NesterovPlace::initNesDatabase(PlacerDB* placer_db) +{ + _nes_database = new NesterovDatabase(); + _nes_database->_placer_db = placer_db; - wrapNesInstanceList(); - wrapNesNetList(); - wrapNesPinList(); - completeConnection(); + wrapNesInstanceList(); + wrapNesNetList(); + wrapNesPinList(); + completeConnection(); - if (_nes_config.isAdaptiveBin()){ - this->calculateAdaptiveBinCnt(); - LOG_INFO << "Change to Adaptive Bin: (" << _nes_config.get_bin_cnt_x() << "," << _nes_config.get_bin_cnt_y() << ")" << std::endl; - } - - initGridManager(); - initTopologyManager(); - notifyPLBinSize(); - initHPWLEvaluator(); - initWAWLGradientEvaluator(); - if (_nes_config.isOptTiming()) { - initTimingAnnotation(); - } + if (_nes_config.isAdaptiveBin()) { + this->calculateAdaptiveBinCnt(); + LOG_INFO << "Change to Adaptive Bin: (" << _nes_config.get_bin_cnt_x() << "," << _nes_config.get_bin_cnt_y() << ")" << std::endl; } - void NesterovPlace::calculateAdaptiveBinCnt() - { - int32_t inst_cnt = _nes_database->_nInstances_range; - int32_t side_cnt = 2; - while(side_cnt*side_cnt < inst_cnt){ - side_cnt *= 2; - } - - int32_t bin_cnt_x = side_cnt; - int32_t bin_cnt_y = side_cnt; - - const Layout* layout = _nes_database->_placer_db->get_layout(); - int32_t core_width = layout->get_core_shape().get_width(); - int32_t core_height = layout->get_core_shape().get_height(); - - if(core_width > core_height){ - bin_cnt_x *= std::pow(2, static_cast(round(static_cast(core_width)/core_height))-1); - }else{ - bin_cnt_y *= std::pow(2, static_cast(round(static_cast(core_height)/core_width))-1); - } - - _nes_config.set_bin_cnt_x(bin_cnt_x); - _nes_config.set_bin_cnt_y(bin_cnt_y); - } - - void NesterovPlace::notifyPLBinSize() { - int32_t bin_size_x = _nes_database->_grid_manager->get_grid_size_x(); - int32_t bin_size_y = _nes_database->_grid_manager->get_grid_size_y(); - - PlacerDBInst.bin_size_x = bin_size_x; - PlacerDBInst.bin_size_y = bin_size_y; + initGridManager(); + initTopologyManager(); + notifyPLBinSize(); + initHPWLEvaluator(); + initWAWLGradientEvaluator(); + if (_nes_config.isOptTiming()) { + initTimingAnnotation(); } +} - void NesterovPlace::wrapNesInstanceList() - { - auto inst_list = _nes_database->_placer_db->get_design()->get_instance_list(); - - for (auto* inst : inst_list) { - // skip the outside inst - if (inst->isOutsideInstance()) { - continue; - } - - NesInstance* n_inst = new NesInstance(inst->get_name()); - - wrapNesInstance(inst, n_inst); - - _nes_database->_nInstance_list.push_back(n_inst); - _nes_database->_nInstance_map.emplace(inst, n_inst); - _nes_database->_instance_map.emplace(n_inst, inst); - n_inst->set_inst_id(_nes_database->_nInstances_range); - _nes_database->_nInstances_range += 1; - } +void NesterovPlace::calculateAdaptiveBinCnt() +{ + int32_t inst_cnt = _nes_database->_nInstances_range; + int32_t side_cnt = 2; + while (side_cnt * side_cnt < inst_cnt) { + side_cnt *= 2; } - void NesterovPlace::wrapNesInstance(Instance* inst, NesInstance* nesInst) - { - nesInst->set_origin_shape(std::move(inst->get_shape())); + int32_t bin_cnt_x = side_cnt; + int32_t bin_cnt_y = side_cnt; - if (inst->isFixed()) { - nesInst->set_fixed(); - } + const Layout* layout = _nes_database->_placer_db->get_layout(); + int32_t core_width = layout->get_core_shape().get_width(); + int32_t core_height = layout->get_core_shape().get_height(); - if (inst->get_cell_master() && inst->get_cell_master()->isMacro()) { - nesInst->set_macro(); - } + if (core_width > core_height) { + bin_cnt_x *= std::pow(2, static_cast(round(static_cast(core_width) / core_height)) - 1); + } else { + bin_cnt_y *= std::pow(2, static_cast(round(static_cast(core_height) / core_width)) - 1); } - void NesterovPlace::wrapNesNetList() - { - for (auto* net : _nes_database->_placer_db->get_design()->get_net_list()) { - NesNet* n_net = new NesNet(net->get_name()); + _nes_config.set_bin_cnt_x(bin_cnt_x); + _nes_config.set_bin_cnt_y(bin_cnt_y); +} - wrapNesNet(net, n_net); +void NesterovPlace::notifyPLBinSize() +{ + int32_t bin_size_x = _nes_database->_grid_manager->get_grid_size_x(); + int32_t bin_size_y = _nes_database->_grid_manager->get_grid_size_y(); - _nes_database->_nNet_list.push_back(n_net); - _nes_database->_nNet_map.emplace(net, n_net); - _nes_database->_net_map.emplace(n_net, net); - n_net->set_net_id(_nes_database->_nNets_range); - _nes_database->_nNets_range += 1; - } - } + PlacerDBInst.bin_size_x = bin_size_x; + PlacerDBInst.bin_size_y = bin_size_y; +} - void NesterovPlace::wrapNesNet(Net* net, NesNet* nesNet) - { - nesNet->set_weight(net->get_net_weight()); +void NesterovPlace::wrapNesInstanceList() +{ + auto inst_list = _nes_database->_placer_db->get_design()->get_instance_list(); - if (net->isDontCareNet()) { - nesNet->set_dont_care(); - } - } + for (auto* inst : inst_list) { + // skip the outside inst + if (inst->isOutsideInstance()) { + continue; + } + + NesInstance* n_inst = new NesInstance(inst->get_name()); + + wrapNesInstance(inst, n_inst); + + _nes_database->_nInstance_list.push_back(n_inst); + _nes_database->_nInstance_map.emplace(inst, n_inst); + _nes_database->_instance_map.emplace(n_inst, inst); + n_inst->set_inst_id(_nes_database->_nInstances_range); + _nes_database->_nInstances_range += 1; + } +} + +void NesterovPlace::wrapNesInstance(Instance* inst, NesInstance* nesInst) +{ + nesInst->set_origin_shape(std::move(inst->get_shape())); + + if (inst->isFixed()) { + nesInst->set_fixed(); + } + + if (inst->get_cell_master() && inst->get_cell_master()->isMacro()) { + nesInst->set_macro(); + } +} + +void NesterovPlace::wrapNesNetList() +{ + for (auto* net : _nes_database->_placer_db->get_design()->get_net_list()) { + NesNet* n_net = new NesNet(net->get_name()); + + wrapNesNet(net, n_net); + + _nes_database->_nNet_list.push_back(n_net); + _nes_database->_nNet_map.emplace(net, n_net); + _nes_database->_net_map.emplace(n_net, net); + n_net->set_net_id(_nes_database->_nNets_range); + _nes_database->_nNets_range += 1; + } +} + +void NesterovPlace::wrapNesNet(Net* net, NesNet* nesNet) +{ + nesNet->set_weight(net->get_net_weight()); + + if (net->isDontCareNet()) { + nesNet->set_dont_care(); + } +} + +void NesterovPlace::wrapNesPinList() +{ + for (auto* pin : _nes_database->_placer_db->get_design()->get_pin_list()) { + NesPin* n_pin = new NesPin(pin->get_name()); - void NesterovPlace::wrapNesPinList() - { - for (auto* pin : _nes_database->_placer_db->get_design()->get_pin_list()) { - NesPin* n_pin = new NesPin(pin->get_name()); - - wrapNesPin(pin, n_pin); - - _nes_database->_nPin_list.push_back(n_pin); - _nes_database->_nPin_map.emplace(pin, n_pin); - _nes_database->_pin_map.emplace(n_pin, pin); - n_pin->set_pin_id(_nes_database->_nPins_range); - _nes_database->_nPins_range += 1; - } + wrapNesPin(pin, n_pin); + + _nes_database->_nPin_list.push_back(n_pin); + _nes_database->_nPin_map.emplace(pin, n_pin); + _nes_database->_pin_map.emplace(n_pin, pin); + n_pin->set_pin_id(_nes_database->_nPins_range); + _nes_database->_nPins_range += 1; } - - void NesterovPlace::wrapNesPin(Pin* pin, NesPin* nesPin) - { - int32_t origin_offset_x = pin->get_offset_coordi().get_x(); - int32_t origin_offset_y = pin->get_offset_coordi().get_y(); +} + +void NesterovPlace::wrapNesPin(Pin* pin, NesPin* nesPin) +{ + int32_t origin_offset_x = pin->get_offset_coordi().get_x(); + int32_t origin_offset_y = pin->get_offset_coordi().get_y(); + + auto* inst = pin->get_instance(); + if (!inst) { + nesPin->set_offset_coordi(Point(origin_offset_x, origin_offset_y)); + } else { + int32_t modify_offset_x = 0; + int32_t modify_offset_y = 0; + + Orient inst_orient = inst->get_orient(); + if (inst_orient == Orient::kN_R0) { + modify_offset_x = origin_offset_x; + modify_offset_y = origin_offset_y; + } else if (inst_orient == Orient::kW_R90) { + modify_offset_x = (-1) * origin_offset_y; + modify_offset_y = origin_offset_x; + } else if (inst_orient == Orient::kS_R180) { + modify_offset_x = (-1) * origin_offset_x; + modify_offset_y = (-1) * origin_offset_y; + } else if (inst_orient == Orient::kFW_MX90) { + modify_offset_x = origin_offset_y; + modify_offset_y = origin_offset_x; + } else if (inst_orient == Orient::kFN_MY) { + modify_offset_x = (-1) * origin_offset_x; + modify_offset_y = origin_offset_y; + } else if (inst_orient == Orient::kFE_MY90) { + modify_offset_x = (-1) * origin_offset_y; + modify_offset_y = (-1) * origin_offset_x; + } else if (inst_orient == Orient::kFS_MX) { + modify_offset_x = origin_offset_x; + modify_offset_y = (-1) * origin_offset_y; + } else if (inst_orient == Orient::kE_R270) { + modify_offset_x = origin_offset_y; + modify_offset_y = (-1) * origin_offset_x; + } else { + LOG_WARNING << inst->get_name() + " has not the orient!"; + } + nesPin->set_offset_coordi(Point(modify_offset_x, modify_offset_y)); + } + nesPin->set_center_coordi(std::move(pin->get_center_coordi())); +} + +void NesterovPlace::completeConnection() +{ + for (auto pair : _nes_database->_nPin_map) { + auto* pin = pair.first; + auto* n_pin = pair.second; auto* inst = pin->get_instance(); - if (!inst) { - nesPin->set_offset_coordi(Point(origin_offset_x, origin_offset_y)); - } - else { - int32_t modify_offset_x = 0; - int32_t modify_offset_y = 0; - - Orient inst_orient = inst->get_orient(); - if (inst_orient == Orient::kN_R0) { - modify_offset_x = origin_offset_x; - modify_offset_y = origin_offset_y; - } - else if (inst_orient == Orient::kW_R90) { - modify_offset_x = (-1) * origin_offset_y; - modify_offset_y = origin_offset_x; - } - else if (inst_orient == Orient::kS_R180) { - modify_offset_x = (-1) * origin_offset_x; - modify_offset_y = (-1) * origin_offset_y; - } - else if (inst_orient == Orient::kFW_MX90) { - modify_offset_x = origin_offset_y; - modify_offset_y = origin_offset_x; - } - else if (inst_orient == Orient::kFN_MY) { - modify_offset_x = (-1) * origin_offset_x; - modify_offset_y = origin_offset_y; - } - else if (inst_orient == Orient::kFE_MY90) { - modify_offset_x = (-1) * origin_offset_y; - modify_offset_y = (-1) * origin_offset_x; - } - else if (inst_orient == Orient::kFS_MX) { - modify_offset_x = origin_offset_x; - modify_offset_y = (-1) * origin_offset_y; - } - else if (inst_orient == Orient::kE_R270) { - modify_offset_x = origin_offset_y; - modify_offset_y = (-1) * origin_offset_x; - } - else { - LOG_WARNING << inst->get_name() + " has not the orient!"; - } - nesPin->set_offset_coordi(Point(modify_offset_x, modify_offset_y)); - } - nesPin->set_center_coordi(std::move(pin->get_center_coordi())); - } - - void NesterovPlace::completeConnection() - { - for (auto pair : _nes_database->_nPin_map) { - auto* pin = pair.first; - auto* n_pin = pair.second; - - auto* inst = pin->get_instance(); - // skip the outside inst. - if (inst && !inst->isOutsideInstance()) { - auto* n_inst = _nes_database->_nInstance_map[inst]; + // skip the outside inst. + if (inst && !inst->isOutsideInstance()) { + auto* n_inst = _nes_database->_nInstance_map[inst]; - n_pin->set_nInstance(n_inst); - n_inst->add_nPin(n_pin); - } + n_pin->set_nInstance(n_inst); + n_inst->add_nPin(n_pin); + } - auto* net = pin->get_net(); - auto* n_net = _nes_database->_nNet_map[net]; + auto* net = pin->get_net(); + auto* n_net = _nes_database->_nNet_map[net]; - n_pin->set_nNet(n_net); + n_pin->set_nNet(n_net); - auto* driver_pin = net->get_driver_pin(); - if (driver_pin) { - if (driver_pin->get_name() == pin->get_name()) { - n_net->set_driver(n_pin); - } - else { - n_net->add_loader(n_pin); - } - } - else { + auto* driver_pin = net->get_driver_pin(); + if (driver_pin) { + if (driver_pin->get_name() == pin->get_name()) { + n_net->set_driver(n_pin); + } else { n_net->add_loader(n_pin); } + } else { + n_net->add_loader(n_pin); + } + } +} + +void NesterovPlace::initGridManager() +{ + Rectangle core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); + int32_t grid_cnt_x = _nes_config.get_bin_cnt_x(); + int32_t grid_cnt_y = _nes_config.get_bin_cnt_y(); + float target_density = _nes_config.get_target_density(); + + GridManager* grid_manager = new GridManager(core_shape, grid_cnt_x, grid_cnt_y, target_density, _nes_config.get_thread_num()); + _nes_database->_grid_manager = grid_manager; + + // BinGrid specially need to parallel + _nes_database->_bin_grid = new BinGrid(grid_manager); + _nes_database->_bin_grid->set_thread_nums(_nes_config.get_thread_num()); + int route_cap_h = _nes_database->_placer_db->get_layout()->get_route_cap_h(); + int route_cap_v = _nes_database->_placer_db->get_layout()->get_route_cap_v(); + int partial_route_cap_h = _nes_database->_placer_db->get_layout()->get_partial_route_cap_h(); + int partial_route_cap_v = _nes_database->_placer_db->get_layout()->get_partial_route_cap_v(); + _nes_database->_bin_grid->set_route_cap_h(route_cap_h); + _nes_database->_bin_grid->set_route_cap_v(route_cap_v); + _nes_database->_bin_grid->set_partial_route_cap_h(partial_route_cap_h); + _nes_database->_bin_grid->set_partial_route_cap_v(partial_route_cap_v); + + _nes_database->_density = new Density(grid_manager); + _nes_database->_density_gradient = new ElectricFieldGradient(grid_manager); // TODO : be optional. +} + +void NesterovPlace::initTopologyManager() +{ + TopologyManager* topo_manager = new TopologyManager(); + _nes_database->_topology_manager = topo_manager; + + this->initNodes(); + this->initNetWorks(); + this->initGroups(); + this->initArcs(); + + if (_nes_config.isOptTiming()) { + topo_manager->updateALLNodeTopoId(); + } +} + +void NesterovPlace::initNodes() +{ + auto* topo_manager = _nes_database->_topology_manager; + for (auto pair : _nes_database->_pin_map) { + auto* n_pin = pair.first; + Node* node = new Node(n_pin->get_name()); + node->set_location(std::move(n_pin->get_center_coordi())); + auto* pl_pin = pair.second; + + // set node type. + if (pl_pin->isInstanceInput() || pl_pin->isIOInput()) { + node->set_node_type(NODE_TYPE::kInput); + } else if (pl_pin->isInstanceOutput() || pl_pin->isIOOutput()) { + node->set_node_type(NODE_TYPE::kOutput); + } else if (pl_pin->isInstanceInputOutput() || pl_pin->isIOInputOutput()) { + node->set_node_type(NODE_TYPE::kInputOutput); + } else { + node->set_node_type(NODE_TYPE::kNone); + } + + // set is io node + if (pl_pin->isIOPort()) { + node->set_is_io(); + } + topo_manager->add_node(node); + node->set_node_id(n_pin->get_pin_id()); // not match in origin order + } + topo_manager->sortNodeList(); +} + +void NesterovPlace::initNetWorks() +{ + auto* topo_manager = _nes_database->_topology_manager; + for (auto pair : _nes_database->_net_map) { + auto* n_net = pair.first; + NetWork* network = new NetWork(n_net->get_name()); + + network->set_net_weight(n_net->get_weight()); + + auto* pl_net = pair.second; + + // set network type. + if (pl_net->isClockNet()) { + network->set_network_type(NETWORK_TYPE::kClock); + } else if (pl_net->isFakeNet()) { + network->set_network_type(NETWORK_TYPE::kFakeNet); + } else if (pl_net->isSignalNet()) { + network->set_network_type(NETWORK_TYPE::kSignal); + } else { + network->set_network_type(NETWORK_TYPE::kNone); + } + + NesPin* driver = n_net->get_driver(); + if (driver) { + Node* transmitter = topo_manager->findNodeById(driver->get_pin_id()); + transmitter->set_network(network); + network->set_transmitter(transmitter); + } + + for (auto* loader : n_net->get_loader_list()) { + Node* receiver = topo_manager->findNodeById(loader->get_pin_id()); + receiver->set_network(network); + network->add_receiver(receiver); + } + + topo_manager->add_network(network); + network->set_network_id(n_net->get_net_id()); // not match in origin order. + } + topo_manager->sortNetworkList(); +} + +void NesterovPlace::initGroups() +{ + auto* topo_manager = _nes_database->_topology_manager; + for (auto pair : _nes_database->_instance_map) { + auto* n_inst = pair.first; + Group* group = new Group(n_inst->get_name()); + + auto* pl_inst = pair.second; + // set group type. + auto* cell_master = pl_inst->get_cell_master(); + if (cell_master) { + if (cell_master->isFlipflop()) { + group->set_group_type(GROUP_TYPE::kFlipflop); + } else if (cell_master->isClockBuffer()) { + group->set_group_type(GROUP_TYPE::kClockBuffer); + } else if (cell_master->isLogicBuffer()) { + group->set_group_type(GROUP_TYPE::kLogicBuffer); + } else if (cell_master->isMacro()) { + group->set_group_type(GROUP_TYPE::kMacro); + } else if (cell_master->isIOCell()) { + group->set_group_type(GROUP_TYPE::kIOCell); + } else if (cell_master->isLogic()) { + group->set_group_type(GROUP_TYPE::kLogic); + } else { + group->set_group_type(GROUP_TYPE::kNone); + } + } else { + group->set_group_type(GROUP_TYPE::kNone); } - } - - void NesterovPlace::initGridManager() - { - Rectangle core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); - int32_t grid_cnt_x = _nes_config.get_bin_cnt_x(); - int32_t grid_cnt_y = _nes_config.get_bin_cnt_y(); - float target_density = _nes_config.get_target_density(); - - GridManager* grid_manager = new GridManager(core_shape, grid_cnt_x, grid_cnt_y, target_density, _nes_config.get_thread_num()); - _nes_database->_grid_manager = grid_manager; - - // BinGrid specially need to parallel - _nes_database->_bin_grid = new BinGrid(grid_manager); - _nes_database->_bin_grid->set_thread_nums(_nes_config.get_thread_num()); - int route_cap_h = _nes_database->_placer_db->get_layout()->get_route_cap_h(); - int route_cap_v = _nes_database->_placer_db->get_layout()->get_route_cap_v(); - int partial_route_cap_h = _nes_database->_placer_db->get_layout()->get_partial_route_cap_h(); - int partial_route_cap_v = _nes_database->_placer_db->get_layout()->get_partial_route_cap_v(); - _nes_database->_bin_grid->set_route_cap_h(route_cap_h); - _nes_database->_bin_grid->set_route_cap_v(route_cap_v); - _nes_database->_bin_grid->set_partial_route_cap_h(partial_route_cap_h); - _nes_database->_bin_grid->set_partial_route_cap_v(partial_route_cap_v); - - _nes_database->_density = new Density(grid_manager); - _nes_database->_density_gradient = new ElectricFieldGradient(grid_manager); // TODO : be optional. - } - - void NesterovPlace::initTopologyManager() - { - TopologyManager* topo_manager = new TopologyManager(); - _nes_database->_topology_manager = topo_manager; - - this->initNodes(); - this->initNetWorks(); - this->initGroups(); - this->initArcs(); - - if (_nes_config.isOptTiming()) { - topo_manager->updateALLNodeTopoId(); - } - } - void NesterovPlace::initNodes() - { - auto* topo_manager = _nes_database->_topology_manager; - for (auto pair : _nes_database->_pin_map) { - auto* n_pin = pair.first; - Node* node = new Node(n_pin->get_name()); - node->set_location(std::move(n_pin->get_center_coordi())); - auto* pl_pin = pair.second; - - // set node type. - if (pl_pin->isInstanceInput() || pl_pin->isIOInput()) { - node->set_node_type(NODE_TYPE::kInput); - } - else if (pl_pin->isInstanceOutput() || pl_pin->isIOOutput()) { - node->set_node_type(NODE_TYPE::kOutput); - } - else if (pl_pin->isInstanceInputOutput() || pl_pin->isIOInputOutput()) { - node->set_node_type(NODE_TYPE::kInputOutput); - } - else { - node->set_node_type(NODE_TYPE::kNone); + for (auto* n_pin : n_inst->get_nPin_list()) { + Node* node = topo_manager->findNodeById(n_pin->get_pin_id()); + node->set_group(group); + group->add_node(node); + } + topo_manager->add_group(group); + group->set_group_id(pl_inst->get_inst_id()); // not match in origin order. + } + topo_manager->sortGroupList(); +} + +void NesterovPlace::initArcs() +{ + auto* topo_manager = _nes_database->_topology_manager; + for (auto* node : topo_manager->get_node_list()) { + // TODO: Consider the INPUT & OUTPUT Case. + if (node->is_io_node()) { + if (node->get_node_type() == NODE_TYPE::kOutput) { + this->generateNetArc(node); + } + + } else { + if (node->get_node_type() == NODE_TYPE::kInput) { + this->generateNetArc(node); + } else if (node->get_node_type() == NODE_TYPE::kOutput) { + this->generateGroupArc(node); + } + } + } + topo_manager->sortArcList(); +} + +void NesterovPlace::generatePortOutNetArc(Node* node) +{ + auto* topo_manager = _nes_database->_topology_manager; + auto* network = node->get_network(); + if (network) { + for (auto* sink_node : network->get_receiver_list()) { + Arc* net_arc = new Arc(node, sink_node); + net_arc->set_arc_type(ARC_TYPE::kNetArc); + node->add_output_arc(net_arc); + sink_node->add_input_arc(net_arc); + topo_manager->add_arc(net_arc); + } + } +} + +void NesterovPlace::generateNetArc(Node* node) +{ + auto* topo_manager = _nes_database->_topology_manager; + auto* network = node->get_network(); + if (network) { + auto* driver_node = network->get_transmitter(); + if (driver_node) { + Arc* net_arc = new Arc(driver_node, node); + net_arc->set_arc_type(ARC_TYPE::kNetArc); + driver_node->add_output_arc(net_arc); + node->add_input_arc(net_arc); + topo_manager->add_arc(net_arc); + } + } +} + +void NesterovPlace::generateGroupArc(Node* node) +{ + auto* topo_manager = _nes_database->_topology_manager; + auto* group = node->get_group(); + if (group) { + auto input_list = group->obtainInputNodes(); + for (auto* input_node : input_list) { + NetWork* input_net = input_node->get_network(); + if (input_net->get_network_type() != NETWORK_TYPE::kClock && group->get_group_type() == GROUP_TYPE::kFlipflop) { + continue; } - // set is io node - if (pl_pin->isIOPort()) { - node->set_is_io(); - } - topo_manager->add_node(node); - node->set_node_id(n_pin->get_pin_id()); // not match in origin order + Arc* group_arc = new Arc(input_node, node); + group_arc->set_arc_type(ARC_TYPE::kGroupArc); + input_node->add_output_arc(group_arc); + node->add_input_arc(group_arc); + topo_manager->add_arc(group_arc); } - topo_manager->sortNodeList(); } +} - void NesterovPlace::initNetWorks() - { - auto* topo_manager = _nes_database->_topology_manager; - for (auto pair : _nes_database->_net_map) { - auto* n_net = pair.first; - NetWork* network = new NetWork(n_net->get_name()); +void NesterovPlace::initHPWLEvaluator() +{ + _nes_database->_wirelength = new HPWirelength(_nes_database->_topology_manager); +} - network->set_net_weight(n_net->get_weight()); +void NesterovPlace::initWAWLGradientEvaluator() +{ + _nes_database->_wirelength_gradient = new WAWirelengthGradient(_nes_database->_topology_manager); +} - auto* pl_net = pair.second; +void NesterovPlace::initTimingAnnotation() +{ + _nes_database->_timing_annotation = new TimingAnnotation(_nes_database->_topology_manager); +} - // set network type. - if (pl_net->isClockNet()) { - network->set_network_type(NETWORK_TYPE::kClock); - } - else if (pl_net->isFakeNet()) { - network->set_network_type(NETWORK_TYPE::kFakeNet); - } - else if (pl_net->isSignalNet()) { - network->set_network_type(NETWORK_TYPE::kSignal); - } - else { - network->set_network_type(NETWORK_TYPE::kNone); - } +void NesterovPlace::initFillerNesInstance() +{ + std::vector edge_x_assemble; + std::vector edge_y_assemble; - NesPin* driver = n_net->get_driver(); - if (driver) { - Node* transmitter = topo_manager->findNodeById(driver->get_pin_id()); - transmitter->set_network(network); - network->set_transmitter(transmitter); - } + // record area. + int64_t nonplace_area = 0; + int64_t occupied_area = 0; - for (auto* loader : n_net->get_loader_list()) { - Node* receiver = topo_manager->findNodeById(loader->get_pin_id()); - receiver->set_network(network); - network->add_receiver(receiver); - } + Rectangle core_rect = _nes_database->_placer_db->get_layout()->get_core_shape(); + PolygonSet ps; + for (auto* n_inst : _nes_database->_nInstance_list) { + Rectangle n_inst_shape = n_inst->get_origin_shape(); + int64_t shape_area_x = static_cast(n_inst_shape.get_width()); + int64_t shape_area_y = static_cast(n_inst_shape.get_height()); - topo_manager->add_network(network); - network->set_network_id(n_net->get_net_id()); // not match in origin order. + // skip fixed nInsts. + if (n_inst->isFixed()) { + ps.insert( + gtl::rectangle_data(n_inst_shape.get_ll_x(), n_inst_shape.get_ll_y(), n_inst_shape.get_ur_x(), n_inst_shape.get_ur_y())); + continue; } - topo_manager->sortNetworkList(); - } - - void NesterovPlace::initGroups() - { - auto* topo_manager = _nes_database->_topology_manager; - for (auto pair : _nes_database->_instance_map) { - auto* n_inst = pair.first; - Group* group = new Group(n_inst->get_name()); - - auto* pl_inst = pair.second; - // set group type. - auto* cell_master = pl_inst->get_cell_master(); - if (cell_master) { - if (cell_master->isFlipflop()) { - group->set_group_type(GROUP_TYPE::kFlipflop); - } - else if (cell_master->isClockBuffer()) { - group->set_group_type(GROUP_TYPE::kClockBuffer); - } - else if (cell_master->isLogicBuffer()) { - group->set_group_type(GROUP_TYPE::kLogicBuffer); - } - else if (cell_master->isMacro()) { - group->set_group_type(GROUP_TYPE::kMacro); - } - else if (cell_master->isIOCell()) { - group->set_group_type(GROUP_TYPE::kIOCell); - } - else if (cell_master->isLogic()) { - group->set_group_type(GROUP_TYPE::kLogic); - } - else { - group->set_group_type(GROUP_TYPE::kNone); - } - }else{ - group->set_group_type(GROUP_TYPE::kNone); - } - - for (auto* n_pin : n_inst->get_nPin_list()) { - Node* node = topo_manager->findNodeById(n_pin->get_pin_id()); - node->set_group(group); - group->add_node(node); - } - topo_manager->add_group(group); - group->set_group_id(pl_inst->get_inst_id()); // not match in origin order. + if (n_inst->isMacro()) { + occupied_area += shape_area_x * shape_area_y * _nes_config.get_target_density(); + } else { + occupied_area += shape_area_x * shape_area_y; } - topo_manager->sortGroupList(); - } - void NesterovPlace::initArcs() { - auto* topo_manager = _nes_database->_topology_manager; - for (auto* node : topo_manager->get_node_list()) { - // TODO: Consider the INPUT & OUTPUT Case. - if (node->is_io_node()) { - if (node->get_node_type() == NODE_TYPE::kOutput) { - this->generateNetArc(node); - } - - } - else { - if (node->get_node_type() == NODE_TYPE::kInput) { - this->generateNetArc(node); - } - else if (node->get_node_type() == NODE_TYPE::kOutput) { - this->generateGroupArc(node); - } - } - } - topo_manager->sortArcList(); - } - - void NesterovPlace::generatePortOutNetArc(Node* node) { - auto* topo_manager = _nes_database->_topology_manager; - auto* network = node->get_network(); - if (network) { - for (auto* sink_node : network->get_receiver_list()) { - Arc* net_arc = new Arc(node, sink_node); - net_arc->set_arc_type(ARC_TYPE::kNetArc); - node->add_output_arc(net_arc); - sink_node->add_input_arc(net_arc); - topo_manager->add_arc(net_arc); - } - } + edge_x_assemble.push_back(shape_area_x); + edge_y_assemble.push_back(shape_area_y); } - - void NesterovPlace::generateNetArc(Node* node) { - auto* topo_manager = _nes_database->_topology_manager; - auto* network = node->get_network(); - if (network) { - auto* driver_node = network->get_transmitter(); - if (driver_node) { - Arc* net_arc = new Arc(driver_node, node); - net_arc->set_arc_type(ARC_TYPE::kNetArc); - driver_node->add_output_arc(net_arc); - node->add_input_arc(net_arc); - topo_manager->add_arc(net_arc); - } + for (auto* blockage : _nes_database->_placer_db->get_design()->get_region_list()) { + for (auto boundary : blockage->get_boundaries()) { + // non_place_instance_area += boundary_width * boundary_height; + auto rect = gtl::rectangle_data(boundary.get_ll_x(), boundary.get_ll_y(), boundary.get_ur_x(), boundary.get_ur_y()); + ps.insert(rect); } } + ps &= gtl::rectangle_data(core_rect.get_ll_x(), core_rect.get_ll_y(), core_rect.get_ur_x(), core_rect.get_ur_y()); - void NesterovPlace::generateGroupArc(Node* node) { - auto* topo_manager = _nes_database->_topology_manager; - auto* group = node->get_group(); - if (group) { - auto input_list = group->obtainInputNodes(); - for (auto* input_node : input_list) { - NetWork* input_net = input_node->get_network(); - if (input_net->get_network_type() != NETWORK_TYPE::kClock && group->get_group_type() == GROUP_TYPE::kFlipflop) { - continue; - } + std::vector> rects; + ps.get_rectangles(rects); - Arc* group_arc = new Arc(input_node, node); - group_arc->set_arc_type(ARC_TYPE::kGroupArc); - input_node->add_output_arc(group_arc); - node->add_input_arc(group_arc); - topo_manager->add_arc(group_arc); - } - } + for (const auto& rect : rects) { + nonplace_area += 1LL * boost::polygon::area(rect); } - void NesterovPlace::initHPWLEvaluator() { - _nes_database->_wirelength = new HPWirelength(_nes_database->_topology_manager); - } + // sort + std::sort(edge_x_assemble.begin(), edge_x_assemble.end()); + std::sort(edge_y_assemble.begin(), edge_y_assemble.end()); - void NesterovPlace::initWAWLGradientEvaluator() { - _nes_database->_wirelength_gradient = new WAWirelengthGradient(_nes_database->_topology_manager); - } + int64_t edge_x_sum = 0, edge_y_sum = 0; - void NesterovPlace::initTimingAnnotation() { - _nes_database->_timing_annotation = new TimingAnnotation(_nes_database->_topology_manager); + int min_idx = edge_x_assemble.size() * 0.05; + int max_idx = edge_y_assemble.size() * 0.95; + for (int i = min_idx; i < max_idx; i++) { + edge_x_sum += edge_x_assemble[i]; + edge_y_sum += edge_y_assemble[i]; } - void NesterovPlace::initFillerNesInstance() - { - std::vector edge_x_assemble; - std::vector edge_y_assemble; - - // record area. - int64_t nonplace_area = 0; - int64_t occupied_area = 0; - - Rectangle core_rect = _nes_database->_placer_db->get_layout()->get_core_shape(); - PolygonSet ps; - for (auto* n_inst : _nes_database->_nInstance_list) { - Rectangle n_inst_shape = n_inst->get_origin_shape(); - int64_t shape_area_x = static_cast(n_inst_shape.get_width()); - int64_t shape_area_y = static_cast(n_inst_shape.get_height()); - - // skip fixed nInsts. - if (n_inst->isFixed()) { - ps.insert(gtl::rectangle_data(n_inst_shape.get_ll_x(), n_inst_shape.get_ll_y(), n_inst_shape.get_ur_x(), n_inst_shape.get_ur_y())); - continue; - } - if (n_inst->isMacro()) { - occupied_area += shape_area_x * shape_area_y * _nes_config.get_target_density(); - } - else { - occupied_area += shape_area_x * shape_area_y; - } - - edge_x_assemble.push_back(shape_area_x); - edge_y_assemble.push_back(shape_area_y); - } - for (auto* blockage : _nes_database->_placer_db->get_design()->get_region_list()) { - for (auto boundary : blockage->get_boundaries()) { - // non_place_instance_area += boundary_width * boundary_height; - auto rect = gtl::rectangle_data(boundary.get_ll_x(), boundary.get_ll_y(), boundary.get_ur_x(), boundary.get_ur_y()); - ps.insert(rect) ; - - } - } - ps &= gtl::rectangle_data(core_rect.get_ll_x(), core_rect.get_ll_y(), core_rect.get_ur_x(), core_rect.get_ur_y()); - - std::vector> rects; - ps.get_rectangles(rects); - - for (const auto &rect : rects) { - nonplace_area += 1LL* boost::polygon::area(rect); - } - - // sort - std::sort(edge_x_assemble.begin(), edge_x_assemble.end()); - std::sort(edge_y_assemble.begin(), edge_y_assemble.end()); + int avg_edge_x = static_cast(edge_x_sum / (max_idx - min_idx)); + int avg_edge_y = static_cast(edge_y_sum / (max_idx - min_idx)); - int64_t edge_x_sum = 0, edge_y_sum = 0; - - int min_idx = edge_x_assemble.size() * 0.05; - int max_idx = edge_y_assemble.size() * 0.95; - for (int i = min_idx; i < max_idx; i++) { - edge_x_sum += edge_x_assemble[i]; - edge_y_sum += edge_y_assemble[i]; - } + Rectangle core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); + int64_t core_area = static_cast(core_shape.get_width()) * static_cast(core_shape.get_height()); + int64_t white_space_area = core_area - nonplace_area; + int64_t movable_area = white_space_area * _nes_config.get_target_density(); + int64_t total_filler_area = movable_area - occupied_area; - int avg_edge_x = static_cast(edge_x_sum / (max_idx - min_idx)); - int avg_edge_y = static_cast(edge_y_sum / (max_idx - min_idx)); + LOG_ERROR_IF(total_filler_area < 0) << "Detect: Negative filler area \n" + << " The reason may be target_density setting: try to improve target_density \n"; - Rectangle core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); - int64_t core_area = static_cast(core_shape.get_width()) * static_cast(core_shape.get_height()); - int64_t white_space_area = core_area - nonplace_area; - int64_t movable_area = white_space_area * _nes_config.get_target_density(); - int64_t total_filler_area = movable_area - occupied_area; + std::mt19937 rand_val(0); - LOG_ERROR_IF(total_filler_area < 0) << "Detect: Negative filler area \n" - << " The reason may be target_density setting: try to improve target_density \n"; + // int32_t filler_cnt = total_filler_area / (avg_edge_x * avg_edge_y); - std::mt19937 rand_val(0); + // test + int32_t filler_cnt = std::ceil(static_cast(static_cast(total_filler_area / (avg_edge_x * avg_edge_y)))); - // int32_t filler_cnt = total_filler_area / (avg_edge_x * avg_edge_y); + for (int i = 0; i < filler_cnt; i++) { + auto rand_x = rand_val(); + auto rand_y = rand_val(); - // test - int32_t filler_cnt = std::ceil(static_cast(static_cast(total_filler_area / (avg_edge_x * avg_edge_y)))); + NesInstance* filler = new NesInstance("filler_" + std::to_string(i)); - for (int i = 0; i < filler_cnt; i++) { - auto rand_x = rand_val(); - auto rand_y = rand_val(); + int32_t center_x = rand_x % core_shape.get_width() + core_shape.get_ll_x(); + int32_t center_y = rand_y % core_shape.get_height() + core_shape.get_ll_y(); + int32_t lower_x = center_x - avg_edge_x / 2; + int32_t lower_y = center_y - avg_edge_y / 2; - NesInstance* filler = new NesInstance("filler_" + std::to_string(i)); + filler->set_filler(); + filler->set_origin_shape(Rectangle(lower_x, lower_y, lower_x + avg_edge_x, lower_y + avg_edge_y)); - int32_t center_x = rand_x % core_shape.get_width() + core_shape.get_ll_x(); - int32_t center_y = rand_y % core_shape.get_height() + core_shape.get_ll_y(); - int32_t lower_x = center_x - avg_edge_x / 2; - int32_t lower_y = center_y - avg_edge_y / 2; - - filler->set_filler(); - filler->set_origin_shape(Rectangle(lower_x, lower_y, lower_x + avg_edge_x, lower_y + avg_edge_y)); - - _nes_database->_nInstance_list.push_back(filler); - filler->set_inst_id(_nes_database->_nInstances_range); - _nes_database->_nInstances_range += 1; - } + _nes_database->_nInstance_list.push_back(filler); + filler->set_inst_id(_nes_database->_nInstances_range); + _nes_database->_nInstances_range += 1; } +} - void NesterovPlace::initNesInstanceDensitySize() - { - for (auto* n_inst : _nes_database->_nInstance_list) { - if (n_inst->isFixed()) { - n_inst->set_density_shape(n_inst->get_origin_shape()); - n_inst->set_density_scale(1.0F); - continue; - } - - float scale_x = 0, scale_y = 0; - int32_t density_size_x = 0, density_size_y = 0; +void NesterovPlace::initNesInstanceDensitySize() +{ + for (auto* n_inst : _nes_database->_nInstance_list) { + if (n_inst->isFixed()) { + n_inst->set_density_shape(n_inst->get_origin_shape()); + n_inst->set_density_scale(1.0F); + continue; + } - Rectangle first_grid_shape = this->obtainFirstGridShape(); + float scale_x = 0, scale_y = 0; + int32_t density_size_x = 0, density_size_y = 0; - int32_t grid_size_x = first_grid_shape.get_width(); - int32_t grid_size_y = first_grid_shape.get_height(); + Rectangle first_grid_shape = this->obtainFirstGridShape(); - Rectangle n_inst_shape = n_inst->get_origin_shape(); - int32_t n_inst_width = n_inst_shape.get_width(); - int32_t n_inst_height = n_inst_shape.get_height(); + int32_t grid_size_x = first_grid_shape.get_width(); + int32_t grid_size_y = first_grid_shape.get_height(); - if (n_inst_width < static_cast(SQRT2 * grid_size_x)) { - scale_x = static_cast(n_inst_width) / (SQRT2 * grid_size_x); - density_size_x = static_cast(SQRT2 * grid_size_x); - } - else { - scale_x = 1.0F; - density_size_x = n_inst_width; - } + Rectangle n_inst_shape = n_inst->get_origin_shape(); + int32_t n_inst_width = n_inst_shape.get_width(); + int32_t n_inst_height = n_inst_shape.get_height(); - if (n_inst_height < static_cast(SQRT2 * grid_size_y)) { - scale_y = static_cast(n_inst_height) / (SQRT2 * grid_size_y); - density_size_y = static_cast(SQRT2 * grid_size_y); - } - else { - scale_y = 1.0F; - density_size_y = n_inst_height; - } + if (n_inst_width < static_cast(SQRT2 * grid_size_x)) { + scale_x = static_cast(n_inst_width) / (SQRT2 * grid_size_x); + density_size_x = static_cast(SQRT2 * grid_size_x); + } else { + scale_x = 1.0F; + density_size_x = n_inst_width; + } - n_inst->set_density_shape(Rectangle(n_inst_shape.get_ll_x(), n_inst_shape.get_ll_y(), n_inst_shape.get_ll_x() + density_size_x, - n_inst_shape.get_ll_y() + density_size_y)); - n_inst->set_density_scale(scale_x * scale_y); + if (n_inst_height < static_cast(SQRT2 * grid_size_y)) { + scale_y = static_cast(n_inst_height) / (SQRT2 * grid_size_y); + density_size_y = static_cast(SQRT2 * grid_size_y); + } else { + scale_y = 1.0F; + density_size_y = n_inst_height; } - } - void NesterovPlace::runNesterovPlace() - { - std::cout << std::endl; - LOG_INFO << "-----------------Start Global Placement-----------------"; - ieda::Stats gp_status; + n_inst->set_density_shape(Rectangle(n_inst_shape.get_ll_x(), n_inst_shape.get_ll_y(), n_inst_shape.get_ll_x() + density_size_x, + n_inst_shape.get_ll_y() + density_size_y)); + n_inst->set_density_scale(scale_x * scale_y); + } +} - std::vector placable_inst_list = std::move(this->obtianPlacableNesInstanceList()); - initNesterovPlace(placable_inst_list); +void NesterovPlace::runNesterovPlace() +{ + std::cout << std::endl; + LOG_INFO << "-----------------Start Global Placement-----------------"; + ieda::Stats gp_status; - // main - NesterovSolve(placable_inst_list); - PlacerDBInst.updateTopoManager(); - PlacerDBInst.updateGridManager(); + std::vector placable_inst_list = std::move(this->obtianPlacableNesInstanceList()); + initNesterovPlace(placable_inst_list); - double time_delta = gp_status.elapsedRunTime(); - LOG_INFO << "Global Placement Total Time Elapsed: " << time_delta << "s"; - LOG_INFO << "-----------------Finish Global Placement-----------------"; - } + // main + NesterovSolve(placable_inst_list); + PlacerDBInst.updateTopoManager(); + PlacerDBInst.updateGridManager(); + double time_delta = gp_status.elapsedRunTime(); + LOG_INFO << "Global Placement Total Time Elapsed: " << time_delta << "s"; + LOG_INFO << "-----------------Finish Global Placement-----------------"; +} - void NesterovPlace::initNesterovPlace(std::vector& inst_list) - { - size_t inst_size = inst_list.size(); +void NesterovPlace::initNesterovPlace(std::vector& inst_list) +{ + size_t inst_size = inst_list.size(); - std::vector> prev_coordi_list(inst_size, Point()); - std::vector> prev_wirelength_grad_list(inst_size, Point()); - std::vector> prev_density_grad_list(inst_size, Point()); - std::vector> prev_sum_grad_list(inst_size, Point()); - std::vector> current_coordi_list(inst_size, Point()); - std::vector> current_wirelength_grad_list(inst_size, Point()); - std::vector> current_density_grad_list(inst_size, Point()); - std::vector> current_sum_grad_list(inst_size, Point()); + std::vector> prev_coordi_list(inst_size, Point()); + std::vector> prev_wirelength_grad_list(inst_size, Point()); + std::vector> prev_density_grad_list(inst_size, Point()); + std::vector> prev_sum_grad_list(inst_size, Point()); + std::vector> current_coordi_list(inst_size, Point()); + std::vector> current_wirelength_grad_list(inst_size, Point()); + std::vector> current_density_grad_list(inst_size, Point()); + std::vector> current_sum_grad_list(inst_size, Point()); - // initial coordi vector. - Rectangle core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); + // initial coordi vector. + Rectangle core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); #pragma omp parallel for num_threads(_nes_config.get_thread_num()) - for (size_t i = 0; i < inst_size; i++) { - auto* n_inst = inst_list[i]; - this->updateDensityCoordiLayoutInside(n_inst, core_shape); - current_coordi_list[i] = Point(n_inst->get_density_center_coordi().get_x(), n_inst->get_density_center_coordi().get_y()); - } + for (size_t i = 0; i < inst_size; i++) { + auto* n_inst = inst_list[i]; + this->updateDensityCoordiLayoutInside(n_inst, core_shape); + current_coordi_list[i] = Point(n_inst->get_density_center_coordi().get_x(), n_inst->get_density_center_coordi().get_y()); + } - initGridFixedArea(); - // update current density gradient force. - _nes_database->_bin_grid->updateBinGrid(inst_list, _nes_config.get_thread_num()); - _nes_database->_density_gradient->updateDensityForce(_nes_config.get_thread_num(), false); + initGridFixedArea(); + // update current density gradient force. + _nes_database->_bin_grid->updateBinGrid(inst_list, _nes_config.get_thread_num()); + _nes_database->_density_gradient->updateDensityForce(_nes_config.get_thread_num(), false); - _total_inst_area = this->obtainTotalArea(inst_list); - float sum_overflow = static_cast(_nes_database->_bin_grid->get_overflow_area_without_filler()) / _total_inst_area; + _total_inst_area = this->obtainTotalArea(inst_list); + float sum_overflow = static_cast(_nes_database->_bin_grid->get_overflow_area_without_filler()) / _total_inst_area; - // update current wirelength gradient force. - initBaseWirelengthCoef(); - updateWirelengthCoef(sum_overflow); - float wirelength_coef = _nes_database->_wirelength_coef; - updateTopologyManager(); - _nes_database->_wirelength_gradient->updateWirelengthForce(wirelength_coef, wirelength_coef, _nes_config.get_min_wirelength_force_bar(), - _nes_config.get_thread_num()); + // update current wirelength gradient force. + initBaseWirelengthCoef(); + updateWirelengthCoef(sum_overflow); + float wirelength_coef = _nes_database->_wirelength_coef; + updateTopologyManager(); + _nes_database->_wirelength_gradient->updateWirelengthForce(wirelength_coef, wirelength_coef, _nes_config.get_min_wirelength_force_bar(), + _nes_config.get_thread_num()); - // update current target penalty object. - updatePenaltyGradient(inst_list, current_sum_grad_list, current_wirelength_grad_list, current_density_grad_list, false); + // update current target penalty object. + updatePenaltyGradient(inst_list, current_sum_grad_list, current_wirelength_grad_list, current_density_grad_list, false); - if (_nes_database->_is_diverged) { - return; - } + if (_nes_database->_is_diverged) { + return; + } - // update initial prev coordinates. + // update initial prev coordinates. #pragma omp parallel for num_threads(_nes_config.get_thread_num()) - for (size_t i = 0; i < inst_size; i++) { - auto* n_inst = inst_list[i]; + for (size_t i = 0; i < inst_size; i++) { + auto* n_inst = inst_list[i]; - int32_t prev_coordi_x + int32_t prev_coordi_x = current_coordi_list[i].get_x() + _nes_config.get_initial_prev_coordi_update_coef() * current_sum_grad_list[i].get_x(); - int32_t prev_coordi_y + int32_t prev_coordi_y = current_coordi_list[i].get_y() + _nes_config.get_initial_prev_coordi_update_coef() * current_sum_grad_list[i].get_y(); - Point prev_coordi(prev_coordi_x, prev_coordi_y); - n_inst->updateDensityCenterLocation(prev_coordi); - this->updateDensityCoordiLayoutInside(n_inst, core_shape); - prev_coordi_list[i] = Point(n_inst->get_density_center_coordi().get_x(), n_inst->get_density_center_coordi().get_y()); - } + Point prev_coordi(prev_coordi_x, prev_coordi_y); + n_inst->updateDensityCenterLocation(prev_coordi); + this->updateDensityCoordiLayoutInside(n_inst, core_shape); + prev_coordi_list[i] = Point(n_inst->get_density_center_coordi().get_x(), n_inst->get_density_center_coordi().get_y()); + } - // update prev density gradient force. - _nes_database->_bin_grid->updateBinGrid(inst_list, _nes_config.get_thread_num()); - _nes_database->_density_gradient->updateDensityForce(_nes_config.get_thread_num(), false); + // update prev density gradient force. + _nes_database->_bin_grid->updateBinGrid(inst_list, _nes_config.get_thread_num()); + _nes_database->_density_gradient->updateDensityForce(_nes_config.get_thread_num(), false); - // update prev wirelength gradient force. - updateTopologyManager(); - _nes_database->_wirelength_gradient->updateWirelengthForce(wirelength_coef, wirelength_coef, _nes_config.get_min_wirelength_force_bar(), - _nes_config.get_thread_num()); + // update prev wirelength gradient force. + updateTopologyManager(); + _nes_database->_wirelength_gradient->updateWirelengthForce(wirelength_coef, wirelength_coef, _nes_config.get_min_wirelength_force_bar(), + _nes_config.get_thread_num()); - // update prev target penalty object. - updatePenaltyGradient(inst_list, prev_sum_grad_list, prev_wirelength_grad_list, prev_density_grad_list, false); + // update prev target penalty object. + updatePenaltyGradient(inst_list, prev_sum_grad_list, prev_wirelength_grad_list, prev_density_grad_list, false); - if (_nes_database->_is_diverged) { - return; - } + if (_nes_database->_is_diverged) { + return; + } - // init quad penalty - initQuadPenaltyCoeff(); + // init quad penalty + initQuadPenaltyCoeff(); - // init density penalty. - _nes_database->_density_penalty + // init density penalty. + _nes_database->_density_penalty = (_nes_database->_wirelength_grad_sum / _nes_database->_density_grad_sum) * _nes_config.get_init_density_penalty(); - // init nesterov solver. - _nes_database->_nesterov_solver->initNesterov(prev_coordi_list, prev_sum_grad_list, current_coordi_list, current_sum_grad_list); + // init nesterov solver. + _nes_database->_nesterov_solver->initNesterov(prev_coordi_list, prev_sum_grad_list, current_coordi_list, current_sum_grad_list); - // Test Preconditon. - // initDiagonalIdentityMatrix(inst_size); - // initDiagonalHkMatrix(inst_list); - // initDiagonalSkMatrix(inst_list); - } + // Test Preconditon. + // initDiagonalIdentityMatrix(inst_size); + // initDiagonalHkMatrix(inst_list); + // initDiagonalSkMatrix(inst_list); +} - std::vector NesterovPlace::obtianPlacableNesInstanceList() - { - std::vector placable_list; - for (auto* n_inst : _nes_database->_nInstance_list) { - if (n_inst->isFixed()) { - continue; - } - placable_list.push_back(n_inst); +std::vector NesterovPlace::obtianPlacableNesInstanceList() +{ + std::vector placable_list; + for (auto* n_inst : _nes_database->_nInstance_list) { + if (n_inst->isFixed()) { + continue; } - return placable_list; + placable_list.push_back(n_inst); } + return placable_list; +} - void NesterovPlace::updateDensityCoordiLayoutInside(NesInstance* n_inst, Rectangle core_shape) - { - int32_t target_lower_x = n_inst->get_density_coordi().get_x(); - int32_t target_lower_y = n_inst->get_density_coordi().get_y(); - int32_t target_edge_x = n_inst->get_density_shape().get_width(); - int32_t target_edge_y = n_inst->get_density_shape().get_height(); +void NesterovPlace::updateDensityCoordiLayoutInside(NesInstance* n_inst, Rectangle core_shape) +{ + int32_t target_lower_x = n_inst->get_density_coordi().get_x(); + int32_t target_lower_y = n_inst->get_density_coordi().get_y(); + int32_t target_edge_x = n_inst->get_density_shape().get_width(); + int32_t target_edge_y = n_inst->get_density_shape().get_height(); - if (target_lower_x < core_shape.get_ll_x()) { - target_lower_x = core_shape.get_ll_x(); - } - - if (target_lower_y < core_shape.get_ll_y()) { - target_lower_y = core_shape.get_ll_y(); - } + if (target_lower_x < core_shape.get_ll_x()) { + target_lower_x = core_shape.get_ll_x(); + } - if (target_lower_x + target_edge_x > core_shape.get_ur_x()) { - target_lower_x = core_shape.get_ur_x() - target_edge_x; - } + if (target_lower_y < core_shape.get_ll_y()) { + target_lower_y = core_shape.get_ll_y(); + } - if (target_lower_y + target_edge_y > core_shape.get_ur_y()) { - target_lower_y = core_shape.get_ur_y() - target_edge_y; - } + if (target_lower_x + target_edge_x > core_shape.get_ur_x()) { + target_lower_x = core_shape.get_ur_x() - target_edge_x; + } - n_inst->updateDensityLocation(Point(target_lower_x, target_lower_y)); + if (target_lower_y + target_edge_y > core_shape.get_ur_y()) { + target_lower_y = core_shape.get_ur_y() - target_edge_y; } - void NesterovPlace::updateDensityCenterCoordiLayoutInside(NesInstance* n_inst, Point& center_coordi, Rectangle core_shape) - { - int32_t target_edge_x = n_inst->get_density_shape().get_width(); - int32_t target_edge_y = n_inst->get_density_shape().get_height(); + n_inst->updateDensityLocation(Point(target_lower_x, target_lower_y)); +} - int32_t target_lower_x = center_coordi.get_x() - 0.5 * target_edge_x; - int32_t target_lower_y = center_coordi.get_y() - 0.5 * target_edge_y; +void NesterovPlace::updateDensityCenterCoordiLayoutInside(NesInstance* n_inst, Point& center_coordi, Rectangle core_shape) +{ + int32_t target_edge_x = n_inst->get_density_shape().get_width(); + int32_t target_edge_y = n_inst->get_density_shape().get_height(); - if (target_lower_x < core_shape.get_ll_x()) { - target_lower_x = core_shape.get_ll_x(); - } + int32_t target_lower_x = center_coordi.get_x() - 0.5 * target_edge_x; + int32_t target_lower_y = center_coordi.get_y() - 0.5 * target_edge_y; - if (target_lower_y < core_shape.get_ll_y()) { - target_lower_y = core_shape.get_ll_y(); - } + if (target_lower_x < core_shape.get_ll_x()) { + target_lower_x = core_shape.get_ll_x(); + } - if (target_lower_x + target_edge_x > core_shape.get_ur_x()) { - target_lower_x = core_shape.get_ur_x() - target_edge_x; - } + if (target_lower_y < core_shape.get_ll_y()) { + target_lower_y = core_shape.get_ll_y(); + } - if (target_lower_y + target_edge_y > core_shape.get_ur_y()) { - target_lower_y = core_shape.get_ur_y() - target_edge_y; - } + if (target_lower_x + target_edge_x > core_shape.get_ur_x()) { + target_lower_x = core_shape.get_ur_x() - target_edge_x; + } - center_coordi = Point(target_lower_x + std::ceil(0.5 * target_edge_x), target_lower_y + std::ceil(0.5 * target_edge_y)); + if (target_lower_y + target_edge_y > core_shape.get_ur_y()) { + target_lower_y = core_shape.get_ur_y() - target_edge_y; } - void NesterovPlace::initGridFixedArea() - { - auto* grid_manager = _nes_database->_grid_manager; + center_coordi = Point(target_lower_x + std::ceil(0.5 * target_edge_x), target_lower_y + std::ceil(0.5 * target_edge_y)); +} - grid_manager->clearAllOccupiedArea(); +void NesterovPlace::initGridFixedArea() +{ + auto* grid_manager = _nes_database->_grid_manager; - // #pragma omp parallel for num_threads(_nes_config.get_thread_num()) - for (auto* n_inst : _nes_database->_nInstance_list) { - if (!n_inst->isFixed()) { - continue; - } + grid_manager->clearAllOccupiedArea(); - std::vector overlap_grid_list; - auto origin_shape = std::move(n_inst->get_origin_shape()); - grid_manager->obtainOverlapGridList(overlap_grid_list, origin_shape); - for (auto* grid : overlap_grid_list) { - int64_t overlap_area = grid_manager->obtainOverlapArea(grid, n_inst->get_origin_shape()); - - // #pragma omp atomic - grid->fixed_area += overlap_area * grid->available_ratio; - // grid->add_fixed_area(overlap_area * grid->get_available_ratio()); - } + // #pragma omp parallel for num_threads(_nes_config.get_thread_num()) + for (auto* n_inst : _nes_database->_nInstance_list) { + if (!n_inst->isFixed()) { + continue; } - // add blockage. - auto region_list = _nes_database->_placer_db->get_design()->get_region_list(); - for (auto* region : region_list) { - if (region->isFence()) { - std::vector overlap_grid_list; - for (auto boundary : region->get_boundaries()) { - grid_manager->obtainOverlapGridList(overlap_grid_list, boundary); - for (auto* grid : overlap_grid_list) { - // tmp fix overlap area between fixed inst and blockage. - if (grid->fixed_area != 0) { - continue; - } - - // if (grid->get_fixed_area() != 0) { - // continue; - // } - int64_t overlap_area = grid_manager->obtainOverlapArea(grid, boundary); - - grid->fixed_area += overlap_area * grid->available_ratio; - // grid->add_fixed_area(overlap_area * grid->get_available_ratio()); - } - } - } - } - } - - void NesterovPlace::updateTopologyManager() - { - auto* topo_manager = _nes_database->_topology_manager; - int32_t thread_num = _nes_config.get_thread_num(); + std::vector overlap_grid_list; + auto origin_shape = std::move(n_inst->get_origin_shape()); + grid_manager->obtainOverlapGridList(overlap_grid_list, origin_shape); + for (auto* grid : overlap_grid_list) { + int64_t overlap_area = grid_manager->obtainOverlapArea(grid, n_inst->get_origin_shape()); - int32_t net_chunk_size = std::max(int(_nes_database->_nNet_list.size() / thread_num / 16), 1); -#pragma omp parallel for num_threads(thread_num) schedule(dynamic, net_chunk_size) - for (auto* n_net : _nes_database->_nNet_list) { - if (n_net->isDontCare()) { - continue; - } - auto* network = topo_manager->findNetworkById(n_net->get_net_id()); - network->set_net_weight(n_net->get_weight()); + // #pragma omp atomic + grid->fixed_area += overlap_area * grid->available_ratio; + // grid->add_fixed_area(overlap_area * grid->get_available_ratio()); } - - int32_t pin_chunk_size = std::max(int(_nes_database->_nPin_list.size() / thread_num / 16), 1); -#pragma omp parallel for num_threads(thread_num) schedule(dynamic, pin_chunk_size) - for (auto* n_pin : _nes_database->_nPin_list) { - auto* node = topo_manager->findNodeById(n_pin->get_pin_id()); - node->set_location(n_pin->get_center_coordi()); - } - } - - Rectangle NesterovPlace::obtainFirstGridShape() - { - auto& first_grid = _nes_database->_grid_manager->get_grid_2d_list()[0][0]; - - return first_grid.shape; - - // auto* first_grid = _nes_database->_grid_manager->get_row_list()[0]->get_grid_list()[0]; - - // return first_grid->get_shape(); } - int64_t NesterovPlace::obtainTotalArea(std::vector& inst_list) - { - int64_t total_area = 0; - for (auto* n_inst : inst_list) { - if (n_inst->isFiller()) { - continue; - } + // add blockage. + auto region_list = _nes_database->_placer_db->get_design()->get_region_list(); + for (auto* region : region_list) { + if (region->isFence()) { + std::vector overlap_grid_list; + for (auto boundary : region->get_boundaries()) { + grid_manager->obtainOverlapGridList(overlap_grid_list, boundary); + for (auto* grid : overlap_grid_list) { + // tmp fix overlap area between fixed inst and blockage. + if (grid->fixed_area != 0) { + continue; + } - int64_t n_inst_width = static_cast(n_inst->get_origin_shape().get_width()); - int64_t n_inst_height = static_cast(n_inst->get_origin_shape().get_height()); + // if (grid->get_fixed_area() != 0) { + // continue; + // } + int64_t overlap_area = grid_manager->obtainOverlapArea(grid, boundary); - if (n_inst->isMacro()) { - total_area += static_cast(n_inst_width * n_inst_height * _nes_config.get_target_density()); - } - else { - total_area += n_inst_width * n_inst_height; + grid->fixed_area += overlap_area * grid->available_ratio; + // grid->add_fixed_area(overlap_area * grid->get_available_ratio()); + } } } - - return total_area; } +} - int64_t NesterovPlace::obtainTotalFillerArea(std::vector& inst_list) - { - int64_t total_filler_area = 0; +void NesterovPlace::updateTopologyManager() +{ + auto* topo_manager = _nes_database->_topology_manager; + int32_t thread_num = _nes_config.get_thread_num(); - for (auto* n_inst : inst_list) { - if (n_inst->isFiller()) { - int64_t n_inst_width = static_cast(n_inst->get_origin_shape().get_width()); - int64_t n_inst_height = static_cast(n_inst->get_origin_shape().get_height()); - total_filler_area += n_inst_width * n_inst_height; - } + int32_t net_chunk_size = std::max(int(_nes_database->_nNet_list.size() / thread_num / 16), 1); +#pragma omp parallel for num_threads(thread_num) schedule(dynamic, net_chunk_size) + for (auto* n_net : _nes_database->_nNet_list) { + if (n_net->isDontCare()) { + continue; } - - return total_filler_area; + auto* network = topo_manager->findNetworkById(n_net->get_net_id()); + network->set_net_weight(n_net->get_weight()); } - void NesterovPlace::initBaseWirelengthCoef() - { - Rectangle first_grid_shape = this->obtainFirstGridShape(); - _nes_database->_base_wirelength_coef - = _nes_config.get_init_wirelength_coef() / (static_cast(first_grid_shape.get_half_perimeter()) * 0.5); + int32_t pin_chunk_size = std::max(int(_nes_database->_nPin_list.size() / thread_num / 16), 1); +#pragma omp parallel for num_threads(thread_num) schedule(dynamic, pin_chunk_size) + for (auto* n_pin : _nes_database->_nPin_list) { + auto* node = topo_manager->findNodeById(n_pin->get_pin_id()); + node->set_location(n_pin->get_center_coordi()); } +} - void NesterovPlace::updateWirelengthCoef(float overflow) - { - if (overflow > 1.0) { - _nes_database->_wirelength_coef = 0.1; - } - else if (overflow < 0.1) { - _nes_database->_wirelength_coef = 10.0; - } - else { - _nes_database->_wirelength_coef = 1.0 / pow(10.0, (overflow - 0.1) * 20 / 9.0 - 1.0); - } +Rectangle NesterovPlace::obtainFirstGridShape() +{ + auto& first_grid = _nes_database->_grid_manager->get_grid_2d_list()[0][0]; - _nes_database->_wirelength_coef *= _nes_database->_base_wirelength_coef; - } + return first_grid.shape; - void NesterovPlace::initDiagonalIdentityMatrix(int32_t inst_size) - { - _global_diagonal_list.resize(2 * inst_size, 1.0); - } + // auto* first_grid = _nes_database->_grid_manager->get_row_list()[0]->get_grid_list()[0]; - void NesterovPlace::initDiagonalHkMatrix(std::vector& inst_list) - { - size_t inst_size = inst_list.size(); - _global_diagonal_list.resize(2 * inst_size, 1.0); + // return first_grid->get_shape(); +} - for (size_t i = 0; i < inst_size; i++) { - auto* cur_n_inst = inst_list[i]; - Point wirelength_precondition = std::move(obtainWirelengthPrecondition(cur_n_inst)); - Point density_precondition = std::move(obtainDensityPrecondition(cur_n_inst)); - float coeff = wirelength_precondition.get_x() + _nes_database->_density_penalty * density_precondition.get_x(); - _global_diagonal_list[i] = static_cast(coeff); - _global_diagonal_list[inst_size + i] = static_cast(coeff); +int64_t NesterovPlace::obtainTotalArea(std::vector& inst_list) +{ + int64_t total_area = 0; + for (auto* n_inst : inst_list) { + if (n_inst->isFiller()) { + continue; } - } - void NesterovPlace::initDiagonalSkMatrix(std::vector& inst_list) - { - size_t inst_size = inst_list.size(); - _global_diagonal_list.resize(2 * inst_size, 1.0); + int64_t n_inst_width = static_cast(n_inst->get_origin_shape().get_width()); + int64_t n_inst_height = static_cast(n_inst->get_origin_shape().get_height()); - for (size_t i = 0; i < inst_size; i++) { - auto* cur_n_inst = inst_list[i]; - Point wirelength_precondition = std::move(obtainWirelengthPrecondition(cur_n_inst)); - Point density_precondition = std::move(obtainDensityPrecondition(cur_n_inst)); - float coeff = wirelength_precondition.get_x() + _nes_database->_density_penalty * density_precondition.get_x(); - _global_diagonal_list[i] = static_cast(1 / coeff); - _global_diagonal_list[inst_size + i] = static_cast(1 / coeff); + if (n_inst->isMacro()) { + total_area += static_cast(n_inst_width * n_inst_height * _nes_config.get_target_density()); + } else { + total_area += n_inst_width * n_inst_height; } } - void NesterovPlace::updatePenaltyGradientPre1(std::vector& nInst_list, std::vector>& sum_grads, - std::vector>& wirelength_grads, std::vector>& density_grads) - { - // if((_nes_database->_nesterov_solver->get_current_iter()) % 100 == 0){ - // LOG_INFO << "Iteration: "<< _nes_database->_nesterov_solver->get_current_iter() <<" Reset precondition."; - // _global_diagonal_list.clear(); - // initDiagonalHkMatrix(nInst_list); - // } - _nes_database->_density_grad_sum = 0.0F; + return total_area; +} - // const auto& front_coordi_list = _nes_database->_nesterov_solver->get_current_coordis(); - // const auto& current_coordi_list = _nes_database->_nesterov_solver->get_next_coordis(); - // const auto& front_grad_list = _nes_database->_nesterov_solver->get_current_grads(); - // const auto& current_grad_list = _nes_database->_nesterov_solver->get_next_grads(); +int64_t NesterovPlace::obtainTotalFillerArea(std::vector& inst_list) +{ + int64_t total_filler_area = 0; - // // prcondition method 1 - // size_t inst_size = nInst_list.size(); - // std::vector front_ski_x(inst_size); - // std::vector front_ski_y(inst_size); - // std::vector front_yki_x(inst_size); - // std::vector front_yki_y(inst_size); - // double sk2hk_variable = 0.0; - // double yksk_variable = 0.0; - // for(size_t i=0; i < inst_size; i++){ - // front_ski_x[i] = current_coordi_list[i].get_x() - front_coordi_list[i].get_x(); - // front_ski_y[i] = current_coordi_list[i].get_y() - front_coordi_list[i].get_y(); - // sk2hk_variable += (front_ski_x[i] * front_ski_x[i] * _global_diagonal_list[i]); - // sk2hk_variable += (front_ski_y[i] * front_ski_y[i] * _global_diagonal_list[i+inst_size]); - - // front_yki_x[i] = current_grad_list[i].get_x() - front_grad_list[i].get_x(); - // front_yki_y[i] = current_grad_list[i].get_y() - front_grad_list[i].get_y(); - // yksk_variable += (front_yki_x[i] * front_ski_x[i] + front_yki_y[i] * front_ski_y[i]); - // } + for (auto* n_inst : inst_list) { + if (n_inst->isFiller()) { + int64_t n_inst_width = static_cast(n_inst->get_origin_shape().get_width()); + int64_t n_inst_height = static_cast(n_inst->get_origin_shape().get_height()); + total_filler_area += n_inst_width * n_inst_height; + } + } - for (size_t i = 0; i < nInst_list.size(); i++) { - auto& cur_n_inst = nInst_list[i]; + return total_filler_area; +} - wirelength_grads[i] = std::move(_nes_database->_wirelength_gradient->obtainWirelengthGradient( +void NesterovPlace::initBaseWirelengthCoef() +{ + Rectangle first_grid_shape = this->obtainFirstGridShape(); + _nes_database->_base_wirelength_coef + = _nes_config.get_init_wirelength_coef() / (static_cast(first_grid_shape.get_half_perimeter()) * 0.5); +} + +void NesterovPlace::updateWirelengthCoef(float overflow) +{ + if (overflow > 1.0) { + _nes_database->_wirelength_coef = 0.1; + } else if (overflow < 0.1) { + _nes_database->_wirelength_coef = 10.0; + } else { + _nes_database->_wirelength_coef = 1.0 / pow(10.0, (overflow - 0.1) * 20 / 9.0 - 1.0); + } + + _nes_database->_wirelength_coef *= _nes_database->_base_wirelength_coef; +} + +void NesterovPlace::initDiagonalIdentityMatrix(int32_t inst_size) +{ + _global_diagonal_list.resize(2 * inst_size, 1.0); +} + +void NesterovPlace::initDiagonalHkMatrix(std::vector& inst_list) +{ + size_t inst_size = inst_list.size(); + _global_diagonal_list.resize(2 * inst_size, 1.0); + + for (size_t i = 0; i < inst_size; i++) { + auto* cur_n_inst = inst_list[i]; + Point wirelength_precondition = std::move(obtainWirelengthPrecondition(cur_n_inst)); + Point density_precondition = std::move(obtainDensityPrecondition(cur_n_inst)); + float coeff = wirelength_precondition.get_x() + _nes_database->_density_penalty * density_precondition.get_x(); + _global_diagonal_list[i] = static_cast(coeff); + _global_diagonal_list[inst_size + i] = static_cast(coeff); + } +} + +void NesterovPlace::initDiagonalSkMatrix(std::vector& inst_list) +{ + size_t inst_size = inst_list.size(); + _global_diagonal_list.resize(2 * inst_size, 1.0); + + for (size_t i = 0; i < inst_size; i++) { + auto* cur_n_inst = inst_list[i]; + Point wirelength_precondition = std::move(obtainWirelengthPrecondition(cur_n_inst)); + Point density_precondition = std::move(obtainDensityPrecondition(cur_n_inst)); + float coeff = wirelength_precondition.get_x() + _nes_database->_density_penalty * density_precondition.get_x(); + _global_diagonal_list[i] = static_cast(1 / coeff); + _global_diagonal_list[inst_size + i] = static_cast(1 / coeff); + } +} + +void NesterovPlace::updatePenaltyGradientPre1(std::vector& nInst_list, std::vector>& sum_grads, + std::vector>& wirelength_grads, std::vector>& density_grads) +{ + // if((_nes_database->_nesterov_solver->get_current_iter()) % 100 == 0){ + // LOG_INFO << "Iteration: "<< _nes_database->_nesterov_solver->get_current_iter() <<" Reset precondition."; + // _global_diagonal_list.clear(); + // initDiagonalHkMatrix(nInst_list); + // } + _nes_database->_density_grad_sum = 0.0F; + + // const auto& front_coordi_list = _nes_database->_nesterov_solver->get_current_coordis(); + // const auto& current_coordi_list = _nes_database->_nesterov_solver->get_next_coordis(); + // const auto& front_grad_list = _nes_database->_nesterov_solver->get_current_grads(); + // const auto& current_grad_list = _nes_database->_nesterov_solver->get_next_grads(); + + // // prcondition method 1 + // size_t inst_size = nInst_list.size(); + // std::vector front_ski_x(inst_size); + // std::vector front_ski_y(inst_size); + // std::vector front_yki_x(inst_size); + // std::vector front_yki_y(inst_size); + // double sk2hk_variable = 0.0; + // double yksk_variable = 0.0; + // for(size_t i=0; i < inst_size; i++){ + // front_ski_x[i] = current_coordi_list[i].get_x() - front_coordi_list[i].get_x(); + // front_ski_y[i] = current_coordi_list[i].get_y() - front_coordi_list[i].get_y(); + // sk2hk_variable += (front_ski_x[i] * front_ski_x[i] * _global_diagonal_list[i]); + // sk2hk_variable += (front_ski_y[i] * front_ski_y[i] * _global_diagonal_list[i+inst_size]); + + // front_yki_x[i] = current_grad_list[i].get_x() - front_grad_list[i].get_x(); + // front_yki_y[i] = current_grad_list[i].get_y() - front_grad_list[i].get_y(); + // yksk_variable += (front_yki_x[i] * front_ski_x[i] + front_yki_y[i] * front_ski_y[i]); + // } + + for (size_t i = 0; i < nInst_list.size(); i++) { + auto& cur_n_inst = nInst_list[i]; + + wirelength_grads[i] = std::move(_nes_database->_wirelength_gradient->obtainWirelengthGradient( cur_n_inst->get_inst_id(), _nes_database->_wirelength_coef, _nes_database->_wirelength_coef)); - density_grads[i] = std::move( + density_grads[i] = std::move( _nes_database->_density_gradient->obtainDensityGradient(cur_n_inst->get_density_shape(), cur_n_inst->get_density_scale(), 0, 0.0f)); - _nes_database->_wirelength_grad_sum += fabs(wirelength_grads[i].get_x()); - _nes_database->_wirelength_grad_sum += fabs(wirelength_grads[i].get_y()); - - _nes_database->_density_grad_sum += fabs(density_grads[i].get_x()); - _nes_database->_density_grad_sum += fabs(density_grads[i].get_y()); - - sum_grads[i].set_x(wirelength_grads[i].get_x() + _nes_database->_density_penalty * density_grads[i].get_x()); - sum_grads[i].set_y(wirelength_grads[i].get_y() + _nes_database->_density_penalty * density_grads[i].get_y()); + _nes_database->_wirelength_grad_sum += fabs(wirelength_grads[i].get_x()); + _nes_database->_wirelength_grad_sum += fabs(wirelength_grads[i].get_y()); - // // prcondition method 1 - // double hksk_x = _global_diagonal_list[i] * front_ski_x[i]; - // double hksk_y = _global_diagonal_list[inst_size + i] * front_ski_y[i]; - // float hki_x = static_cast(_global_diagonal_list[i] - (hksk_x * hksk_x) / sk2hk_variable + (front_yki_x[i] * front_yki_x[i]) / - // yksk_variable); float hki_y = static_cast(_global_diagonal_list[inst_size + i] - (hksk_y * hksk_y) / sk2hk_variable + - // (front_yki_y[i] * front_yki_y[i]) / yksk_variable); Point sum_precondition(hki_x,hki_y); + _nes_database->_density_grad_sum += fabs(density_grads[i].get_x()); + _nes_database->_density_grad_sum += fabs(density_grads[i].get_y()); - // if (sum_precondition.get_x() <= _nes_config.get_min_precondition()) { - // sum_precondition.set_x(_nes_config.get_min_precondition()); - // } - // if (sum_precondition.get_y() <= _nes_config.get_min_precondition()) { - // sum_precondition.set_y(_nes_config.get_min_precondition()); - // } + sum_grads[i].set_x(wirelength_grads[i].get_x() + _nes_database->_density_penalty * density_grads[i].get_x()); + sum_grads[i].set_y(wirelength_grads[i].get_y() + _nes_database->_density_penalty * density_grads[i].get_y()); - Point sum_precondition(1.0, 1.0); + // // prcondition method 1 + // double hksk_x = _global_diagonal_list[i] * front_ski_x[i]; + // double hksk_y = _global_diagonal_list[inst_size + i] * front_ski_y[i]; + // float hki_x = static_cast(_global_diagonal_list[i] - (hksk_x * hksk_x) / sk2hk_variable + (front_yki_x[i] * front_yki_x[i]) / + // yksk_variable); float hki_y = static_cast(_global_diagonal_list[inst_size + i] - (hksk_y * hksk_y) / sk2hk_variable + + // (front_yki_y[i] * front_yki_y[i]) / yksk_variable); Point sum_precondition(hki_x,hki_y); + + // if (sum_precondition.get_x() <= _nes_config.get_min_precondition()) { + // sum_precondition.set_x(_nes_config.get_min_precondition()); + // } + // if (sum_precondition.get_y() <= _nes_config.get_min_precondition()) { + // sum_precondition.set_y(_nes_config.get_min_precondition()); + // } - sum_grads[i].set_x(sum_grads[i].get_x() / sum_precondition.get_x()); - sum_grads[i].set_y(sum_grads[i].get_y() / sum_precondition.get_y()); + Point sum_precondition(1.0, 1.0); - // _global_diagonal_list[i] = hki_x; - // _global_diagonal_list[inst_size + i] = hki_y; - } + sum_grads[i].set_x(sum_grads[i].get_x() / sum_precondition.get_x()); + sum_grads[i].set_y(sum_grads[i].get_y() / sum_precondition.get_y()); - if (std::isnan(_nes_database->_wirelength_grad_sum) || std::isinf(_nes_database->_wirelength_grad_sum) - || std::isnan(_nes_database->_density_grad_sum) || std::isinf(_nes_database->_density_grad_sum)) { - _nes_database->_is_diverged = true; - } + // _global_diagonal_list[i] = hki_x; + // _global_diagonal_list[inst_size + i] = hki_y; } - void NesterovPlace::updatePenaltyGradientPre2(std::vector& nInst_list, std::vector>& sum_grads, - std::vector>& wirelength_grads, std::vector>& density_grads) - { - _nes_database->_wirelength_grad_sum = 0.0F; - _nes_database->_density_grad_sum = 0.0F; - - const auto& front_coordi_list = _nes_database->_nesterov_solver->get_current_coordis(); - const auto& current_coordi_list = _nes_database->_nesterov_solver->get_next_coordis(); - const auto& front_grad_list = _nes_database->_nesterov_solver->get_current_grads(); - const auto& current_grad_list = _nes_database->_nesterov_solver->get_next_grads(); - - // prcondition method 2 - size_t inst_size = nInst_list.size(); - std::vector front_ski_x(inst_size); - std::vector front_ski_y(inst_size); - std::vector front_yki_x(inst_size); - std::vector front_yki_y(inst_size); - double yksk_variable = 0.0; - for (size_t i = 0; i < inst_size; i++) { - front_ski_x[i] = current_coordi_list[i].get_x() - front_coordi_list[i].get_x(); - front_ski_y[i] = current_coordi_list[i].get_y() - front_coordi_list[i].get_y(); - front_yki_x[i] = current_grad_list[i].get_x() - front_grad_list[i].get_x(); - front_yki_y[i] = current_grad_list[i].get_y() - front_grad_list[i].get_y(); - yksk_variable += (front_yki_x[i] * front_ski_x[i] + front_yki_y[i] * front_ski_y[i]); - } - - for (size_t i = 0; i < nInst_list.size(); i++) { - auto& cur_n_inst = nInst_list[i]; - - wirelength_grads[i] = std::move(_nes_database->_wirelength_gradient->obtainWirelengthGradient( + if (std::isnan(_nes_database->_wirelength_grad_sum) || std::isinf(_nes_database->_wirelength_grad_sum) + || std::isnan(_nes_database->_density_grad_sum) || std::isinf(_nes_database->_density_grad_sum)) { + _nes_database->_is_diverged = true; + } +} + +void NesterovPlace::updatePenaltyGradientPre2(std::vector& nInst_list, std::vector>& sum_grads, + std::vector>& wirelength_grads, std::vector>& density_grads) +{ + _nes_database->_wirelength_grad_sum = 0.0F; + _nes_database->_density_grad_sum = 0.0F; + + const auto& front_coordi_list = _nes_database->_nesterov_solver->get_current_coordis(); + const auto& current_coordi_list = _nes_database->_nesterov_solver->get_next_coordis(); + const auto& front_grad_list = _nes_database->_nesterov_solver->get_current_grads(); + const auto& current_grad_list = _nes_database->_nesterov_solver->get_next_grads(); + + // prcondition method 2 + size_t inst_size = nInst_list.size(); + std::vector front_ski_x(inst_size); + std::vector front_ski_y(inst_size); + std::vector front_yki_x(inst_size); + std::vector front_yki_y(inst_size); + double yksk_variable = 0.0; + for (size_t i = 0; i < inst_size; i++) { + front_ski_x[i] = current_coordi_list[i].get_x() - front_coordi_list[i].get_x(); + front_ski_y[i] = current_coordi_list[i].get_y() - front_coordi_list[i].get_y(); + front_yki_x[i] = current_grad_list[i].get_x() - front_grad_list[i].get_x(); + front_yki_y[i] = current_grad_list[i].get_y() - front_grad_list[i].get_y(); + yksk_variable += (front_yki_x[i] * front_ski_x[i] + front_yki_y[i] * front_ski_y[i]); + } + + for (size_t i = 0; i < nInst_list.size(); i++) { + auto& cur_n_inst = nInst_list[i]; + + wirelength_grads[i] = std::move(_nes_database->_wirelength_gradient->obtainWirelengthGradient( cur_n_inst->get_inst_id(), _nes_database->_wirelength_coef, _nes_database->_wirelength_coef)); - density_grads[i] = std::move( + density_grads[i] = std::move( _nes_database->_density_gradient->obtainDensityGradient(cur_n_inst->get_density_shape(), cur_n_inst->get_density_scale(), 0, 0.0f)); - _nes_database->_wirelength_grad_sum += fabs(wirelength_grads[i].get_x()); - _nes_database->_wirelength_grad_sum += fabs(wirelength_grads[i].get_y()); + _nes_database->_wirelength_grad_sum += fabs(wirelength_grads[i].get_x()); + _nes_database->_wirelength_grad_sum += fabs(wirelength_grads[i].get_y()); - _nes_database->_density_grad_sum += fabs(density_grads[i].get_x()); - _nes_database->_density_grad_sum += fabs(density_grads[i].get_y()); + _nes_database->_density_grad_sum += fabs(density_grads[i].get_x()); + _nes_database->_density_grad_sum += fabs(density_grads[i].get_y()); - sum_grads[i].set_x(wirelength_grads[i].get_x() + _nes_database->_density_penalty * density_grads[i].get_x()); - sum_grads[i].set_y(wirelength_grads[i].get_y() + _nes_database->_density_penalty * density_grads[i].get_y()); + sum_grads[i].set_x(wirelength_grads[i].get_x() + _nes_database->_density_penalty * density_grads[i].get_x()); + sum_grads[i].set_y(wirelength_grads[i].get_y() + _nes_database->_density_penalty * density_grads[i].get_y()); - // prcondition method 2 - double bk_coeff_x = (1.0 - front_ski_x[i] * front_yki_x[i] / yksk_variable); - double bk_coeff_y = (1.0 - front_ski_y[i] * front_yki_y[i] / yksk_variable); - float bki_x + // prcondition method 2 + double bk_coeff_x = (1.0 - front_ski_x[i] * front_yki_x[i] / yksk_variable); + double bk_coeff_y = (1.0 - front_ski_y[i] * front_yki_y[i] / yksk_variable); + float bki_x = static_cast((bk_coeff_x * bk_coeff_x * _global_diagonal_list[i]) + (front_ski_x[i] * front_ski_x[i]) / yksk_variable); - float bki_y = static_cast((bk_coeff_y * bk_coeff_y * _global_diagonal_list[inst_size + i]) - + (front_ski_y[i] * front_ski_y[i]) / yksk_variable); - Point sum_precondition(bki_x, bki_y); + float bki_y = static_cast((bk_coeff_y * bk_coeff_y * _global_diagonal_list[inst_size + i]) + + (front_ski_y[i] * front_ski_y[i]) / yksk_variable); + Point sum_precondition(bki_x, bki_y); - if (sum_precondition.get_x() >= _nes_config.get_min_precondition()) { - sum_precondition.set_x(_nes_config.get_min_precondition()); - } - if (sum_precondition.get_y() >= _nes_config.get_min_precondition()) { - sum_precondition.set_y(_nes_config.get_min_precondition()); - } + if (sum_precondition.get_x() >= _nes_config.get_min_precondition()) { + sum_precondition.set_x(_nes_config.get_min_precondition()); + } + if (sum_precondition.get_y() >= _nes_config.get_min_precondition()) { + sum_precondition.set_y(_nes_config.get_min_precondition()); + } - sum_grads[i].set_x(sum_grads[i].get_x() * sum_precondition.get_x()); - sum_grads[i].set_y(sum_grads[i].get_y() * sum_precondition.get_y()); + sum_grads[i].set_x(sum_grads[i].get_x() * sum_precondition.get_x()); + sum_grads[i].set_y(sum_grads[i].get_y() * sum_precondition.get_y()); - _global_diagonal_list[i] = bki_x; - _global_diagonal_list[inst_size + i] = bki_y; - } + _global_diagonal_list[i] = bki_x; + _global_diagonal_list[inst_size + i] = bki_y; + } - if (std::isnan(_nes_database->_wirelength_grad_sum) || std::isinf(_nes_database->_wirelength_grad_sum) + if (std::isnan(_nes_database->_wirelength_grad_sum) || std::isinf(_nes_database->_wirelength_grad_sum) || std::isnan(_nes_database->_density_grad_sum) || std::isinf(_nes_database->_density_grad_sum)) { - _nes_database->_is_diverged = true; - } + _nes_database->_is_diverged = true; } +} - void NesterovPlace::updatePenaltyGradient(std::vector& nInst_list, std::vector>& sum_grads, - std::vector>& wirelength_grads, std::vector>& density_grads, - bool is_add_quad_penalty) - { - _nes_database->_wirelength_grad_sum = 0.0F; - _nes_database->_density_grad_sum = 0.0F; +void NesterovPlace::updatePenaltyGradient(std::vector& nInst_list, std::vector>& sum_grads, + std::vector>& wirelength_grads, std::vector>& density_grads, + bool is_add_quad_penalty) +{ + _nes_database->_wirelength_grad_sum = 0.0F; + _nes_database->_density_grad_sum = 0.0F; #pragma omp parallel for num_threads(_nes_config.get_thread_num()) - for (size_t i = 0; i < nInst_list.size(); i++) { - auto& cur_n_inst = nInst_list[i]; + for (size_t i = 0; i < nInst_list.size(); i++) { + auto& cur_n_inst = nInst_list[i]; - wirelength_grads[i] = std::move(_nes_database->_wirelength_gradient->obtainWirelengthGradient( + wirelength_grads[i] = std::move(_nes_database->_wirelength_gradient->obtainWirelengthGradient( cur_n_inst->get_inst_id(), _nes_database->_wirelength_coef, _nes_database->_wirelength_coef)); - density_grads[i] = std::move(_nes_database->_density_gradient->obtainDensityGradient( + density_grads[i] = std::move(_nes_database->_density_gradient->obtainDensityGradient( cur_n_inst->get_density_shape(), cur_n_inst->get_density_scale(), is_add_quad_penalty, _quad_penalty_coeff)); - } - - float density_penalty = _nes_database->_density_penalty; - if (is_add_quad_penalty) { - density_penalty *= (1.0 + 2 * _quad_penalty_coeff * _nes_database->_density_gradient->get_sum_phi()); - density_penalty *= 2; - } + } - for (size_t i = 0; i < nInst_list.size(); i++) { - auto& cur_n_inst = nInst_list[i]; - _nes_database->_wirelength_grad_sum += fabs(wirelength_grads[i].get_x()); - _nes_database->_wirelength_grad_sum += fabs(wirelength_grads[i].get_y()); + float density_penalty = _nes_database->_density_penalty; + if (is_add_quad_penalty) { + density_penalty *= (1.0 + 2 * _quad_penalty_coeff * _nes_database->_density_gradient->get_sum_phi()); + density_penalty *= 2; + } - _nes_database->_density_grad_sum += fabs(density_grads[i].get_x()); - _nes_database->_density_grad_sum += fabs(density_grads[i].get_y()); + for (size_t i = 0; i < nInst_list.size(); i++) { + auto& cur_n_inst = nInst_list[i]; + _nes_database->_wirelength_grad_sum += fabs(wirelength_grads[i].get_x()); + _nes_database->_wirelength_grad_sum += fabs(wirelength_grads[i].get_y()); - sum_grads[i].set_x(wirelength_grads[i].get_x() + density_penalty * density_grads[i].get_x()); - sum_grads[i].set_y(wirelength_grads[i].get_y() + density_penalty * density_grads[i].get_y()); + _nes_database->_density_grad_sum += fabs(density_grads[i].get_x()); + _nes_database->_density_grad_sum += fabs(density_grads[i].get_y()); - Point wirelength_precondition = std::move(obtainWirelengthPrecondition(cur_n_inst)); - Point density_precondition = std::move(obtainDensityPrecondition(cur_n_inst)); - Point sum_precondition(wirelength_precondition.get_x() + _nes_database->_density_penalty * density_precondition.get_x(), - wirelength_precondition.get_y() + _nes_database->_density_penalty * density_precondition.get_y()); + sum_grads[i].set_x(wirelength_grads[i].get_x() + density_penalty * density_grads[i].get_x()); + sum_grads[i].set_y(wirelength_grads[i].get_y() + density_penalty * density_grads[i].get_y()); - if (sum_precondition.get_x() <= _nes_config.get_min_precondition()) { - sum_precondition.set_x(_nes_config.get_min_precondition()); - } - if (sum_precondition.get_y() <= _nes_config.get_min_precondition()) { - sum_precondition.set_y(_nes_config.get_min_precondition()); - } + Point wirelength_precondition = std::move(obtainWirelengthPrecondition(cur_n_inst)); + Point density_precondition = std::move(obtainDensityPrecondition(cur_n_inst)); + Point sum_precondition(wirelength_precondition.get_x() + _nes_database->_density_penalty * density_precondition.get_x(), + wirelength_precondition.get_y() + _nes_database->_density_penalty * density_precondition.get_y()); - sum_grads[i].set_x(sum_grads[i].get_x() / sum_precondition.get_x()); - sum_grads[i].set_y(sum_grads[i].get_y() / sum_precondition.get_y()); + if (sum_precondition.get_x() <= _nes_config.get_min_precondition()) { + sum_precondition.set_x(_nes_config.get_min_precondition()); } - - if (std::isnan(_nes_database->_wirelength_grad_sum) || std::isinf(_nes_database->_wirelength_grad_sum) - || std::isnan(_nes_database->_density_grad_sum) || std::isinf(_nes_database->_density_grad_sum)) { - _nes_database->_is_diverged = true; + if (sum_precondition.get_y() <= _nes_config.get_min_precondition()) { + sum_precondition.set_y(_nes_config.get_min_precondition()); } - } - Point NesterovPlace::obtainWirelengthPrecondition(NesInstance* n_inst) - { - float wl_factor = 0.0; - for (auto* n_pin : n_inst->get_nPin_list()) { - wl_factor += n_pin->get_nNet()->get_weight(); - } - return Point(wl_factor, wl_factor); + sum_grads[i].set_x(sum_grads[i].get_x() / sum_precondition.get_x()); + sum_grads[i].set_y(sum_grads[i].get_y() / sum_precondition.get_y()); } - Point NesterovPlace::obtainDensityPrecondition(NesInstance* n_inst) - { - float n_inst_width = static_cast(n_inst->get_origin_shape().get_width()); - float n_inst_height = static_cast(n_inst->get_origin_shape().get_height()); - - float area_val = n_inst_width * n_inst_height; - return Point(area_val, area_val); - } + if (std::isnan(_nes_database->_wirelength_grad_sum) || std::isinf(_nes_database->_wirelength_grad_sum) + || std::isnan(_nes_database->_density_grad_sum) || std::isinf(_nes_database->_density_grad_sum)) { + _nes_database->_is_diverged = true; + } +} + +Point NesterovPlace::obtainWirelengthPrecondition(NesInstance* n_inst) +{ + float wl_factor = 0.0; + for (auto* n_pin : n_inst->get_nPin_list()) { + wl_factor += n_pin->get_nNet()->get_weight(); + } + return Point(wl_factor, wl_factor); +} + +Point NesterovPlace::obtainDensityPrecondition(NesInstance* n_inst) +{ + float n_inst_width = static_cast(n_inst->get_origin_shape().get_width()); + float n_inst_height = static_cast(n_inst->get_origin_shape().get_height()); + + float area_val = n_inst_width * n_inst_height; + return Point(area_val, area_val); +} + +float NesterovPlace::obtainPhiCoef(float scaled_diff_hpwl, int32_t iteration_num) +{ + float ret_coef = (scaled_diff_hpwl < 0) ? _nes_config.get_max_phi_coef() * std::max(std::pow(0.9999, float(iteration_num)), 0.98) + : _nes_config.get_max_phi_coef() * pow(_nes_config.get_max_phi_coef(), scaled_diff_hpwl * -1.0); + ret_coef = std::min(_nes_config.get_max_phi_coef(), ret_coef); + ret_coef = std::max(_nes_config.get_min_phi_coef(), ret_coef); + return ret_coef; +} + +void NesterovPlace::NesterovSolve(std::vector& inst_list) +{ + // diverged control. + if (_nes_database->_is_diverged) { + LOG_ERROR << "Detect diverged, The reason may be parameters setting."; + return; + } + + auto* solver = _nes_database->_nesterov_solver; + size_t inst_size = inst_list.size(); + + float sum_overflow; + int64_t prev_hpwl, hpwl; + prev_hpwl = _nes_database->_wirelength->obtainTotalWirelength(); + + std::vector> next_slp_wirelength_grad_list(inst_size, Point()); + std::vector> next_slp_density_grad_list(inst_size, Point()); + std::vector> next_slp_sum_grad_list(inst_size, Point()); + + float sum_overflow_threshold = 1e25; + float hpwl_attach_sum_overflow = 1e25; + bool max_phi_coef_record = false; + + Rectangle core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); + + // opt setting + const std::vector& opt_overflow_list = _nes_config.get_opt_overflow_list(); + int32_t cur_opt_overflow_step = opt_overflow_list.size() - 1; + + // prepare for long net opt. + int32_t long_width, long_height; + std::ofstream long_net_stream; + if (PRINT_LONG_NET) { + float layout_ratio = 0.5; + long_width = core_shape.get_width() * layout_ratio; + long_height = core_shape.get_height() * layout_ratio; + long_net_stream.open(iPLAPIInst.obtainTargetDir() + "/pl/AcrossLongNet_process.txt"); + if (!long_net_stream.good()) { + LOG_WARNING << "Cannot open file for recording across long net !"; + } + } + + // prepare for iter info record + std::ofstream info_stream; + if (RECORD_ITER_INFO) { + info_stream.open(iPLAPIInst.obtainTargetDir() + "/pl/plIterInfo.csv"); + if (!info_stream.good()) { + LOG_WARNING << "Cannot open file for iter info record !"; + } + } + + // prepare for convergence acceleration and non-convergence treatment + int32_t min_perturb_interval = 50; + int32_t last_perturb_iter = -min_perturb_interval; + bool is_add_quad_penalty = false; + bool is_cal_phi = false; + bool stop_placement = false; + std::vector> best_position_list; + std::vector> cur_position_list; + best_position_list.resize(inst_size); + cur_position_list.resize(inst_size); + + if (_nes_config.isOptCongestion()) { + _nes_database->_bin_grid->evalRouteCap(_nes_config.get_thread_num()); + // _nes_database->_bin_grid->plotRouteCap(); + } + + // algorithm core loop. + for (int32_t iter_num = 1; iter_num <= _nes_config.get_max_iter(); iter_num++) { + solver->runNextIter(iter_num, _nes_config.get_thread_num()); + int32_t num_backtrack = 0; + for (; num_backtrack < _nes_config.get_max_back_track(); num_backtrack++) { + auto& next_coordi_list = solver->get_next_coordis(); + auto& next_slp_coordi_list = solver->get_next_slp_coordis(); - float NesterovPlace::obtainPhiCoef(float scaled_diff_hpwl, int32_t iteration_num) - { - float ret_coef = (scaled_diff_hpwl < 0) ? _nes_config.get_max_phi_coef() * std::max(std::pow(0.9999, float(iteration_num)), 0.98) - : _nes_config.get_max_phi_coef() * pow(_nes_config.get_max_phi_coef(), scaled_diff_hpwl * -1.0); - ret_coef = std::min(_nes_config.get_max_phi_coef(), ret_coef); - ret_coef = std::max(_nes_config.get_min_phi_coef(), ret_coef); - return ret_coef; - } +#pragma omp parallel for num_threads(_nes_config.get_thread_num()) + for (size_t i = 0; i < inst_size; i++) { + Point next_coordi(next_coordi_list[i].get_x(), next_coordi_list[i].get_y()); + Point next_slp_coordi(next_slp_coordi_list[i].get_x(), next_slp_coordi_list[i].get_y()); - void NesterovPlace::NesterovSolve(std::vector& inst_list) - { - // diverged control. - if (_nes_database->_is_diverged) { - LOG_ERROR << "Detect diverged, The reason may be parameters setting."; - return; - } + updateDensityCenterCoordiLayoutInside(inst_list[i], next_coordi, core_shape); + solver->correctNextCoordi(i, next_coordi); + cur_position_list[i] = next_coordi; - auto* solver = _nes_database->_nesterov_solver; - size_t inst_size = inst_list.size(); - - float sum_overflow; - int64_t prev_hpwl, hpwl; - prev_hpwl = _nes_database->_wirelength->obtainTotalWirelength(); - - std::vector> next_slp_wirelength_grad_list(inst_size, Point()); - std::vector> next_slp_density_grad_list(inst_size, Point()); - std::vector> next_slp_sum_grad_list(inst_size, Point()); - - float sum_overflow_threshold = 1e25; - float hpwl_attach_sum_overflow = 1e25; - bool max_phi_coef_record = false; - - Rectangle core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); - - // opt setting - const std::vector& opt_overflow_list = _nes_config.get_opt_overflow_list(); - int32_t cur_opt_overflow_step = opt_overflow_list.size() - 1; - - // prepare for long net opt. - int32_t long_width, long_height; - std::ofstream long_net_stream; - if (PRINT_LONG_NET) { - float layout_ratio = 0.5; - long_width = core_shape.get_width() * layout_ratio; - long_height = core_shape.get_height() * layout_ratio; - long_net_stream.open(iPLAPIInst.obtainTargetDir() + "/pl/AcrossLongNet_process.txt"); - if (!long_net_stream.good()) { - LOG_WARNING << "Cannot open file for recording across long net !"; + updateDensityCenterCoordiLayoutInside(inst_list[i], next_slp_coordi, core_shape); + solver->correctNextSLPCoordi(i, next_slp_coordi); + inst_list[i]->updateDensityCenterLocation(next_slp_coordi); } - } - // prepare for iter info record - std::ofstream info_stream; - if (RECORD_ITER_INFO) { - info_stream.open(iPLAPIInst.obtainTargetDir() + "/pl/plIterInfo.csv"); - if (!info_stream.good()) { - LOG_WARNING << "Cannot open file for iter info record !"; + _nes_database->_bin_grid->updateBinGrid(inst_list, _nes_config.get_thread_num()); + + // print density map for debug + if (iter_num == 60 && PRINT_DENSITY_MAP) { + printDensityMapToCsv("density_map_" + std::to_string(iter_num)); } - } - // prepare for convergence acceleration and non-convergence treatment - int32_t min_perturb_interval = 50; - int32_t last_perturb_iter = -min_perturb_interval; - bool is_add_quad_penalty = false; - bool is_cal_phi = false; - bool stop_placement = false; - std::vector> best_position_list; - std::vector> cur_position_list; - best_position_list.resize(inst_size); - cur_position_list.resize(inst_size); - - if (_nes_config.isOptCongestion()){ - _nes_database->_bin_grid->evalRouteCap(_nes_config.get_thread_num()); - // _nes_database->_bin_grid->plotRouteCap(); - } + _nes_database->_density_gradient->updateDensityForce(_nes_config.get_thread_num(), is_cal_phi); - // algorithm core loop. - for (int32_t iter_num = 1; iter_num <= _nes_config.get_max_iter(); iter_num++) { - solver->runNextIter(iter_num, _nes_config.get_thread_num()); - int32_t num_backtrack = 0; - for (; num_backtrack < _nes_config.get_max_back_track(); num_backtrack++) { - auto& next_coordi_list = solver->get_next_coordis(); - auto& next_slp_coordi_list = solver->get_next_slp_coordis(); + updateTopologyManager(); -#pragma omp parallel for num_threads(_nes_config.get_thread_num()) - for (size_t i = 0; i < inst_size; i++) { - Point next_coordi(next_coordi_list[i].get_x(), next_coordi_list[i].get_y()); - Point next_slp_coordi(next_slp_coordi_list[i].get_x(), next_slp_coordi_list[i].get_y()); + sum_overflow = static_cast(_nes_database->_bin_grid->get_overflow_area_without_filler()) / _total_inst_area; + // The following parameters threshold "iter_num" and "sum_overflow" for congestion optimization can be adjusted + if (_nes_config.isOptCongestion() && iter_num >= 200 && iter_num % 10 == 0) { + _nes_database->_bin_grid->evalRouteDem(_nes_database->_topology_manager->get_network_list(), _nes_config.get_thread_num()); + _nes_database->_bin_grid->fastGaussianBlur(); + _nes_database->_bin_grid->evalRouteUtil(); + // _nes_database->_bin_grid->plotRouteUtil(iter_num); + } - updateDensityCenterCoordiLayoutInside(inst_list[i], next_coordi, core_shape); - solver->correctNextCoordi(i, next_coordi); - cur_position_list[i] = next_coordi; + if (!_nes_config.isOptCongestion()) { + _nes_database->_wirelength_gradient->updateWirelengthForce(_nes_database->_wirelength_coef, _nes_database->_wirelength_coef, + _nes_config.get_min_wirelength_force_bar(), + _nes_config.get_thread_num()); + } else { + if (sum_overflow > 0.5) { + _nes_database->_wirelength_gradient->updateWirelengthForce(_nes_database->_wirelength_coef, _nes_database->_wirelength_coef, + _nes_config.get_min_wirelength_force_bar(), + _nes_config.get_thread_num()); + } else { + // LUT-RUDY based congestion-driven optimization. + _nes_database->_bin_grid->evalRouteDem(_nes_database->_topology_manager->get_network_list(), _nes_config.get_thread_num()); + _nes_database->_bin_grid->fastGaussianBlur(); + _nes_database->_bin_grid->evalRouteUtil(); + // _nes_database->_bin_grid->plotOverflowUtil(sum_overflow, iter_num); - updateDensityCenterCoordiLayoutInside(inst_list[i], next_slp_coordi, core_shape); - solver->correctNextSLPCoordi(i, next_slp_coordi); - inst_list[i]->updateDensityCenterLocation(next_slp_coordi); - } + // TODO: GR based congestion-driven optimization. + // writeBackPlacerDB(); + // PlacerDBInst.writeBackSourceDataBase(); + // eval::EvalAPI& eval_api = eval::EvalAPI::initInst(); + // std::vector gr_congestion = eval_api.evalGRCong(); - _nes_database->_bin_grid->updateBinGrid(inst_list, _nes_config.get_thread_num()); - // print density map for debug - if (iter_num == 60 && PRINT_DENSITY_MAP) { - printDensityMapToCsv("density_map_" + std::to_string(iter_num)); - } + auto grid_manager = _nes_database->_bin_grid->get_grid_manager(); + _nes_database->_wirelength_gradient->updateWirelengthForceDirect(_nes_database->_wirelength_coef, _nes_database->_wirelength_coef, + _nes_config.get_min_wirelength_force_bar(), + _nes_config.get_thread_num(), grid_manager); + } + } - _nes_database->_density_gradient->updateDensityForce(_nes_config.get_thread_num(), is_cal_phi); + // update next target penalty object. + updatePenaltyGradient(inst_list, next_slp_sum_grad_list, next_slp_wirelength_grad_list, next_slp_density_grad_list, is_add_quad_penalty); - updateTopologyManager(); + if (_nes_database->_is_diverged) { + break; + } - sum_overflow = static_cast(_nes_database->_bin_grid->get_overflow_area_without_filler()) / _total_inst_area; - if (_nes_config.isOptCongestion() && iter_num >= 340 && iter_num % 10 == 0){ - _nes_database->_bin_grid->evalRouteDem(_nes_database->_topology_manager->get_network_list(), _nes_config.get_thread_num()); - _nes_database->_bin_grid->fastGaussianBlur(); - _nes_database->_bin_grid->evalRouteUtil(); - // _nes_database->_bin_grid->plotRouteUtil(iter_num); - } + float current_steplength = solver->get_next_steplength(); + solver->calculateNextSteplength(next_slp_sum_grad_list); + float next_steplength = solver->get_next_steplength(); - if (!_nes_config.isOptCongestion()){ - _nes_database->_wirelength_gradient->updateWirelengthForce(_nes_database->_wirelength_coef, _nes_database->_wirelength_coef, - _nes_config.get_min_wirelength_force_bar(), _nes_config.get_thread_num()); - }else{ - if (sum_overflow > 0.5){ - _nes_database->_wirelength_gradient->updateWirelengthForce(_nes_database->_wirelength_coef, _nes_database->_wirelength_coef, - _nes_config.get_min_wirelength_force_bar(), _nes_config.get_thread_num()); - }else{ - - _nes_database->_bin_grid->evalRouteDem(_nes_database->_topology_manager->get_network_list(), _nes_config.get_thread_num()); - _nes_database->_bin_grid->fastGaussianBlur(); - _nes_database->_bin_grid->evalRouteUtil(); - // _nes_database->_bin_grid->plotOverflowUtil(sum_overflow, iter_num); - - // writeBackPlacerDB(); - // PlacerDBInst.writeBackSourceDataBase(); - // eval::EvalAPI& eval_api = eval::EvalAPI::initInst(); - // std::vector gr_congestion = eval_api.evalGRCong(); - - auto grid_manager = _nes_database->_bin_grid->get_grid_manager(); - _nes_database->_wirelength_gradient->updateWirelengthForceDirect(_nes_database->_wirelength_coef, _nes_database->_wirelength_coef, - _nes_config.get_min_wirelength_force_bar(), _nes_config.get_thread_num(), grid_manager); - } - } + if (next_steplength > current_steplength * 0.95) { + break; + } else { + solver->runBackTrackIter(_nes_config.get_thread_num()); + } +} - // update next target penalty object. - updatePenaltyGradient(inst_list, next_slp_sum_grad_list, next_slp_wirelength_grad_list, next_slp_density_grad_list, - is_add_quad_penalty); +if (num_backtrack == _nes_config.get_max_back_track()) { + LOG_ERROR << "Detect divergence," + << " The reason may be high init_density_penalty value"; + _nes_database->_is_diverged = true; +} - if (_nes_database->_is_diverged) { - break; - } +if (_nes_database->_is_diverged) { + break; +} - float current_steplength = solver->get_next_steplength(); - solver->calculateNextSteplength(next_slp_sum_grad_list); - float next_steplength = solver->get_next_steplength(); +if (RECORD_ITER_INFO) { + if (iter_num == 1) { + info_stream << "WireLength Grad Sum,Density Grad Sum,Density Weight,StepLength" << std::endl; + } + printIterInfoToCsv(info_stream, iter_num); +} - if (next_steplength > current_steplength * 0.95) { - break; - } - else { - solver->runBackTrackIter(_nes_config.get_thread_num()); - } - } +if (_nes_config.isOptMaxWirelength()) { + if (cur_opt_overflow_step >= 0 && sum_overflow < opt_overflow_list[cur_opt_overflow_step]) { + // update net weight. + updateMaxLengthNetWeight(); + --cur_opt_overflow_step; + LOG_INFO << "[NesterovSolve] Begin update netweight for max wirelength constraint."; + } +} - if (num_backtrack == _nes_config.get_max_back_track()) { - LOG_ERROR << "Detect divergence," - << " The reason may be high init_density_penalty value"; - _nes_database->_is_diverged = true; - } +if (_nes_config.isOptTiming()) { + if (cur_opt_overflow_step >= 0 && sum_overflow < opt_overflow_list[cur_opt_overflow_step]) { + // update net weight. + updateTimingNetWeight(); + --cur_opt_overflow_step; + LOG_INFO << "[NesterovSolve] Update netweight for timing improvement."; + } +} - if (_nes_database->_is_diverged) { - break; - } +updateWirelengthCoef(sum_overflow); +if (!max_phi_coef_record && sum_overflow < 0.35f) { + max_phi_coef_record = true; + _nes_config.set_max_phi_coef(0.985 * _nes_config.get_max_phi_coef()); +} - if (RECORD_ITER_INFO) { - if (iter_num == 1) { - info_stream << "WireLength Grad Sum,Density Grad Sum,Density Weight,StepLength" << std::endl; - } - printIterInfoToCsv(info_stream, iter_num); - } +hpwl = _nes_database->_wirelength->obtainTotalWirelength(); - if (_nes_config.isOptMaxWirelength()) { - if (cur_opt_overflow_step >= 0 && sum_overflow < opt_overflow_list[cur_opt_overflow_step]) { - // update net weight. - updateMaxLengthNetWeight(); - --cur_opt_overflow_step; - LOG_INFO << "[NesterovSolve] Begin update netweight for max wirelength constraint."; - } - } +float phi_coef = obtainPhiCoef(static_cast(hpwl - prev_hpwl) / _nes_config.get_reference_hpwl(), iter_num); +prev_hpwl = hpwl; +_nes_database->_density_penalty *= phi_coef; - if (_nes_config.isOptTiming()) { - if (cur_opt_overflow_step >= 0 && sum_overflow < opt_overflow_list[cur_opt_overflow_step]) { - // update net weight. - updateTimingNetWeight(); - --cur_opt_overflow_step; - LOG_INFO << "[NesterovSolve] Update netweight for timing improvement."; - } - } +// print info. +if (iter_num == 1 || iter_num % _nes_config.get_info_iter_num() == 0) { + LOG_INFO << "[NesterovSolve] Iter: " << iter_num << " overflow: " << sum_overflow << " HPWL: " << prev_hpwl; - updateWirelengthCoef(sum_overflow); - if (!max_phi_coef_record && sum_overflow < 0.35f) { - max_phi_coef_record = true; - _nes_config.set_max_phi_coef(0.985 * _nes_config.get_max_phi_coef()); - } + if (PRINT_LONG_NET) { + long_net_stream << "CURRENT ITERATION: " << iter_num << std::endl; + long_net_stream << std::endl; + printAcrossLongNet(long_net_stream, long_width, long_height); + } - hpwl = _nes_database->_wirelength->obtainTotalWirelength(); + if (PLOT_IMAGE) { + plotInstImage("inst_" + std::to_string(iter_num)); + plotBinForceLine("bin_" + std::to_string(iter_num)); + } - float phi_coef = obtainPhiCoef(static_cast(hpwl - prev_hpwl) / _nes_config.get_reference_hpwl(), iter_num); - prev_hpwl = hpwl; - _nes_database->_density_penalty *= phi_coef; + if (isJsonOutputEnabled()) { + plotInstJson("inst_" + std::to_string(iter_num), iter_num, sum_overflow); - // print info. - if (iter_num == 1 || iter_num % _nes_config.get_info_iter_num() == 0) { - LOG_INFO << "[NesterovSolve] Iter: " << iter_num << " overflow: " << sum_overflow << " HPWL: " << prev_hpwl; + printDensityMapToCsv("density/density_map_" + std::to_string(iter_num)); + } +} - if (PRINT_LONG_NET) { - long_net_stream << "CURRENT ITERATION: " << iter_num << std::endl; - long_net_stream << std::endl; - printAcrossLongNet(long_net_stream, long_width, long_height); - } +if (iter_num == 1 || iter_num % 5 == 0) { + if (PRINT_COORDI) { + saveNesterovPlaceData(iter_num); + } +} - if (PLOT_IMAGE) { - plotInstImage("inst_" + std::to_string(iter_num)); - plotBinForceLine("bin_" + std::to_string(iter_num)); - } +if (sum_overflow_threshold > sum_overflow) { + sum_overflow_threshold = sum_overflow; + hpwl_attach_sum_overflow = prev_hpwl; +} - if (isJsonOutputEnabled()) { - plotInstJson("inst_" + std::to_string(iter_num), iter_num, sum_overflow); +if (sum_overflow < 0.32f && sum_overflow - sum_overflow_threshold >= 0.05f && hpwl_attach_sum_overflow * 1.25f < prev_hpwl) { + LOG_ERROR << "Detect divergence. \n" + << " The reason may be max_phi_cof value: try to decrease max_phi_cof"; + _nes_database->_is_diverged = true; + break; +} - printDensityMapToCsv("density/density_map_" + std::to_string(iter_num)); - } - } +_overflow_record_list.push_back(sum_overflow); +_hpwl_record_list.push_back(hpwl); - if (iter_num == 1 || iter_num % 5 == 0) { - if (PRINT_COORDI) { - saveNesterovPlaceData(iter_num); - } - } +if (sum_overflow < _best_overflow) { + _best_hpwl = hpwl; + _best_overflow = sum_overflow; + best_position_list.swap(cur_position_list); +} - if (sum_overflow_threshold > sum_overflow) { - sum_overflow_threshold = sum_overflow; - hpwl_attach_sum_overflow = prev_hpwl; - } +if (sum_overflow < _nes_config.get_target_overflow() * 4 && sum_overflow > _nes_config.get_target_overflow() * 1.1) { + if (checkDivergence(3, 0.03 * sum_overflow) || checkLongTimeOverflowUnchanged(100, 0.03 * sum_overflow)) { + // rollback to best pos. + for (size_t i = 0; i < inst_size; i++) { + updateDensityCenterCoordiLayoutInside(inst_list[i], best_position_list[i], core_shape); + } + sum_overflow = _best_overflow; + prev_hpwl = _best_hpwl; - if (sum_overflow < 0.32f && sum_overflow - sum_overflow_threshold >= 0.05f && hpwl_attach_sum_overflow * 1.25f < prev_hpwl) { - LOG_ERROR << "Detect divergence. \n" - << " The reason may be max_phi_cof value: try to decrease max_phi_cof"; - _nes_database->_is_diverged = true; - break; - } + stop_placement = true; + } +} - _overflow_record_list.push_back(sum_overflow); - _hpwl_record_list.push_back(hpwl); +if (iter_num - last_perturb_iter > min_perturb_interval && checkPlateau(50, 0.01)) { + if (sum_overflow > 0.9) { + // quad mode + is_add_quad_penalty = true; + is_cal_phi = true; + LOG_INFO << "Try to enable quadratic penalty for density to accelerate convergence"; + if (sum_overflow > 0.95) { + float noise_intensity = std::min(std::max(40 + (120 - 40) * (sum_overflow - 0.95) * 10, 40.0), 90.0) + * _nes_database->_placer_db->get_layout()->get_site_width(); + entropyInjection(0.996, noise_intensity); + LOG_INFO << "Try to entropy injection with noise intensity = " << noise_intensity << " to help convergence"; + } + last_perturb_iter = iter_num; + } +} - if (sum_overflow < _best_overflow) { - _best_hpwl = hpwl; - _best_overflow = sum_overflow; - best_position_list.swap(cur_position_list); - } +// minimun iteration is 30 +if ((iter_num > 30 && sum_overflow <= _nes_config.get_target_overflow()) || stop_placement) { + if (PRINT_LONG_NET) { + long_net_stream << "CURRENT ITERATION: " << iter_num << std::endl; + long_net_stream << std::endl; + printAcrossLongNet(long_net_stream, long_width, long_height); + long_net_stream.close(); + } - if (sum_overflow < _nes_config.get_target_overflow() * 4 && sum_overflow > _nes_config.get_target_overflow() * 1.1) { - if (checkDivergence(3, 0.03 * sum_overflow) || checkLongTimeOverflowUnchanged(100, 0.03 * sum_overflow)) { - // rollback to best pos. - for (size_t i = 0; i < inst_size; i++) { - updateDensityCenterCoordiLayoutInside(inst_list[i], best_position_list[i], core_shape); - } - sum_overflow = _best_overflow; - prev_hpwl = _best_hpwl; + if (RECORD_ITER_INFO) { + info_stream.close(); + } - stop_placement = true; - } - } + if (PRINT_COORDI) { + saveNesterovPlaceData(iter_num); + } - if (iter_num - last_perturb_iter > min_perturb_interval && checkPlateau(50, 0.01)) { - if (sum_overflow > 0.9) { - // quad mode - is_add_quad_penalty = true; - is_cal_phi = true; - LOG_INFO << "Try to enable quadratic penalty for density to accelerate convergence"; - if (sum_overflow > 0.95) { - float noise_intensity = std::min(std::max(40 + (120 - 40) * (sum_overflow - 0.95) * 10, 40.0), 90.0) - * _nes_database->_placer_db->get_layout()->get_site_width(); - entropyInjection(0.996, noise_intensity); - LOG_INFO << "Try to entropy injection with noise intensity = " << noise_intensity - << " to help convergence"; - } - last_perturb_iter = iter_num; - } - } + LOG_INFO << "[NesterovSolve] Finished with Overflow:" << sum_overflow << " HPWL : " << prev_hpwl; + break; +} +} - // minimun iteration is 30 - if ((iter_num > 30 && sum_overflow <= _nes_config.get_target_overflow()) || stop_placement) { - if (PRINT_LONG_NET) { - long_net_stream << "CURRENT ITERATION: " << iter_num << std::endl; - long_net_stream << std::endl; - printAcrossLongNet(long_net_stream, long_width, long_height); - long_net_stream.close(); - } +if (_nes_database->_is_diverged) { + LOG_ERROR << "Detect divergence, The reason may be parameters setting."; + exit(1); +} - if (RECORD_ITER_INFO) { - info_stream.close(); - } +notifyPLOverflowInfo(sum_overflow); +notifyPLPlaceDensity(); - if (PRINT_COORDI) { - saveNesterovPlaceData(iter_num); - } +// update PlacerDB. +writeBackPlacerDB(); +} - LOG_INFO << "[NesterovSolve] Finished with Overflow:" << sum_overflow << " HPWL : " << prev_hpwl; - break; - } - } +void NesterovPlace::notifyPLOverflowInfo(float final_overflow) +{ + PlacerDBInst.gp_overflow = final_overflow; - if (_nes_database->_is_diverged) { - LOG_ERROR << "Detect divergence, The reason may be parameters setting."; - exit(1); - } + std::vector grid_list; + _nes_database->_grid_manager->obtainOverflowIllegalGridList(grid_list); + PlacerDBInst.gp_overflow_number = grid_list.size(); +} - notifyPLOverflowInfo(sum_overflow); - notifyPLPlaceDensity(); +void NesterovPlace::notifyPLPlaceDensity() +{ + auto* grid_manager = _nes_database->_grid_manager; + PlacerDBInst.place_density[0] = grid_manager->obtainAvgGridDensity(); +} - // update PlacerDB. - writeBackPlacerDB(); - } +void NesterovPlace::plotInstImage(std::string file_name) +{ +#ifdef BUILD_QT + auto core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); + // auto core_shape = _nes_database->_core_shape; + std::vector& inst_list = _nes_database->_nInstance_list; - void NesterovPlace::notifyPLOverflowInfo(float final_overflow) { - PlacerDBInst.gp_overflow = final_overflow; + Image image_ploter(core_shape.get_width(), core_shape.get_height(), _nes_database->_nInstance_list.size()); - std::vector grid_list; - _nes_database->_grid_manager->obtainOverflowIllegalGridList(grid_list); - PlacerDBInst.gp_overflow_number = grid_list.size(); - } + int32_t core_shift_x = core_shape.get_ll_x(); + int32_t core_shift_y = core_shape.get_ll_y(); - void NesterovPlace::notifyPLPlaceDensity() { - auto* grid_manager = _nes_database->_grid_manager; - PlacerDBInst.place_density[0] = grid_manager->obtainAvgGridDensity(); - } + // plot bin + auto bin_grid_shape = _nes_database->_grid_manager->get_shape(); + int32_t bin_cnt_x = _nes_database->_grid_manager->get_grid_cnt_x(); + int32_t bin_cnt_y = _nes_database->_grid_manager->get_grid_cnt_y(); + int32_t bin_width = _nes_database->_grid_manager->get_grid_size_x(); + int32_t bin_height = _nes_database->_grid_manager->get_grid_size_y(); + int32_t bin_grid_x = 0; + int32_t bin_grid_y = 0; - void NesterovPlace::plotInstImage(std::string file_name) - { -#ifdef BUILD_QT - auto core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); - // auto core_shape = _nes_database->_core_shape; - std::vector& inst_list = _nes_database->_nInstance_list; - - Image image_ploter(core_shape.get_width(), core_shape.get_height(), _nes_database->_nInstance_list.size()); - - int32_t core_shift_x = core_shape.get_ll_x(); - int32_t core_shift_y = core_shape.get_ll_y(); - - // plot bin - auto bin_grid_shape = _nes_database->_grid_manager->get_shape(); - int32_t bin_cnt_x = _nes_database->_grid_manager->get_grid_cnt_x(); - int32_t bin_cnt_y = _nes_database->_grid_manager->get_grid_cnt_y(); - int32_t bin_width = _nes_database->_grid_manager->get_grid_size_x(); - int32_t bin_height = _nes_database->_grid_manager->get_grid_size_y(); - int32_t bin_grid_x = 0; - int32_t bin_grid_y = 0; - - for (int32_t i = 0; i < bin_cnt_x; i++) { - image_ploter.drawLine(bin_grid_x, bin_grid_y, bin_grid_x, bin_grid_y + bin_grid_shape.get_height(), IMAGE_COLOR::klightGray); - bin_grid_x += bin_width; - } + for (int32_t i = 0; i < bin_cnt_x; i++) { image_ploter.drawLine(bin_grid_x, bin_grid_y, bin_grid_x, bin_grid_y + bin_grid_shape.get_height(), IMAGE_COLOR::klightGray); + bin_grid_x += bin_width; + } + image_ploter.drawLine(bin_grid_x, bin_grid_y, bin_grid_x, bin_grid_y + bin_grid_shape.get_height(), IMAGE_COLOR::klightGray); - bin_grid_x = 0; - for (int32_t i = 0; i < bin_cnt_y; i++) { - image_ploter.drawLine(bin_grid_x, bin_grid_y, bin_grid_x + bin_grid_shape.get_width(), bin_grid_y, IMAGE_COLOR::klightGray); - bin_grid_y += bin_height; - } + bin_grid_x = 0; + for (int32_t i = 0; i < bin_cnt_y; i++) { image_ploter.drawLine(bin_grid_x, bin_grid_y, bin_grid_x + bin_grid_shape.get_width(), bin_grid_y, IMAGE_COLOR::klightGray); - - for (auto* inst : inst_list = _nes_database->_nInstance_list) { - int32_t inst_real_width = inst->get_origin_shape().get_width(); - int32_t inst_real_height = inst->get_origin_shape().get_height(); - auto inst_center = inst->get_density_center_coordi(); - inst_center.set_x(inst_center.get_x() - core_shift_x); - inst_center.set_y(inst_center.get_y() - core_shift_y); - - if (inst->isFiller()) { - image_ploter.drawRect(inst_center.get_x(), inst_center.get_y(), inst_real_width, inst_real_height, 0.0, IMAGE_COLOR::kBule); - } - else if (inst->isMacro()) { - image_ploter.drawRect(inst_center.get_x(), inst_center.get_y(), inst_real_width, inst_real_height, 0.0, IMAGE_COLOR::kRed); - } - else { - image_ploter.drawRect(inst_center.get_x(), inst_center.get_y(), inst_real_width, inst_real_height, 0.0); - } - } - - image_ploter.save(iPLAPIInst.obtainTargetDir() + "/pl/plot/" + file_name + ".jpg"); -#endif + bin_grid_y += bin_height; } + image_ploter.drawLine(bin_grid_x, bin_grid_y, bin_grid_x + bin_grid_shape.get_width(), bin_grid_y, IMAGE_COLOR::klightGray); - void NesterovPlace::plotInstJson(std::string file_name, int32_t cur_iter, float overflow) - { - auto core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); - std::vector& inst_list = _nes_database->_nInstance_list; - nlohmann::json plot = nlohmann::json::object(); - - // Initialize the plot object - plot["instances"] = nlohmann::json::array(); - plot["real_width"] = core_shape.get_width(); - plot["real_height"] = core_shape.get_height(); - plot["num_obj"] = _nes_database->_nInstance_list.size(); - plot["ll_x"] = core_shape.get_ll_x(); - plot["ll_y"] = core_shape.get_ll_y(); - plot["iter"] = cur_iter; - - int32_t core_shift_x = core_shape.get_ll_x(); - int32_t core_shift_y = core_shape.get_ll_y(); - - for (auto* inst : inst_list) { - int32_t inst_real_width = inst->get_origin_shape().get_width(); - int32_t inst_real_height = inst->get_origin_shape().get_height(); - auto inst_center = inst->get_density_center_coordi(); - inst_center.set_x(inst_center.get_x() - core_shift_x); - inst_center.set_y(inst_center.get_y() - core_shift_y); - - plot["instances"].push_back({{"id", inst->get_inst_id()}, - {"name", inst->get_name()}, - {"x", inst_center.get_x()}, - {"y", inst_center.get_y()}, - {"width", inst_real_width}, - {"height", inst_real_height}, - {"is_macro", inst->isMacro()}, - {"is_filler", inst->isFiller()}}); - } + for (auto* inst : inst_list = _nes_database->_nInstance_list) { + int32_t inst_real_width = inst->get_origin_shape().get_width(); + int32_t inst_real_height = inst->get_origin_shape().get_height(); + auto inst_center = inst->get_density_center_coordi(); + inst_center.set_x(inst_center.get_x() - core_shift_x); + inst_center.set_y(inst_center.get_y() - core_shift_y); - std::ofstream out_file(iPLAPIInst.obtainTargetDir() + "/pl/plot/" + file_name + ".json"); - out_file << plot.dump(2); - out_file.close(); + if (inst->isFiller()) { + image_ploter.drawRect(inst_center.get_x(), inst_center.get_y(), inst_real_width, inst_real_height, 0.0, IMAGE_COLOR::kBule); + } else if (inst->isMacro()) { + image_ploter.drawRect(inst_center.get_x(), inst_center.get_y(), inst_real_width, inst_real_height, 0.0, IMAGE_COLOR::kRed); + } else { + image_ploter.drawRect(inst_center.get_x(), inst_center.get_y(), inst_real_width, inst_real_height, 0.0); + } } - void NesterovPlace::plotBinForceLine(std::string file_name) - { + image_ploter.save(iPLAPIInst.obtainTargetDir() + "/pl/plot/" + file_name + ".jpg"); +#endif +} + +void NesterovPlace::plotInstJson(std::string file_name, int32_t cur_iter, float overflow) +{ + auto core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); + std::vector& inst_list = _nes_database->_nInstance_list; + nlohmann::json plot = nlohmann::json::object(); + + // Initialize the plot object + plot["instances"] = nlohmann::json::array(); + plot["real_width"] = core_shape.get_width(); + plot["real_height"] = core_shape.get_height(); + plot["num_obj"] = _nes_database->_nInstance_list.size(); + plot["ll_x"] = core_shape.get_ll_x(); + plot["ll_y"] = core_shape.get_ll_y(); + plot["iter"] = cur_iter; + + int32_t core_shift_x = core_shape.get_ll_x(); + int32_t core_shift_y = core_shape.get_ll_y(); + + for (auto* inst : inst_list) { + int32_t inst_real_width = inst->get_origin_shape().get_width(); + int32_t inst_real_height = inst->get_origin_shape().get_height(); + auto inst_center = inst->get_density_center_coordi(); + inst_center.set_x(inst_center.get_x() - core_shift_x); + inst_center.set_y(inst_center.get_y() - core_shift_y); + + plot["instances"].push_back({{"id", inst->get_inst_id()}, + {"name", inst->get_name()}, + {"x", inst_center.get_x()}, + {"y", inst_center.get_y()}, + {"width", inst_real_width}, + {"height", inst_real_height}, + {"is_macro", inst->isMacro()}, + {"is_filler", inst->isFiller()}}); + } + + std::ofstream out_file(iPLAPIInst.obtainTargetDir() + "/pl/plot/" + file_name + ".json"); + out_file << plot.dump(2); + out_file.close(); +} + +void NesterovPlace::plotBinForceLine(std::string file_name) +{ #ifdef BUILD_QT - auto core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); - // auto core_shape = _nes_database->_core_shape; - auto& force_2d_x_list = _nes_database->_density_gradient->get_force_2d_x_list(); - auto& force_2d_y_list = _nes_database->_density_gradient->get_force_2d_y_list(); - - Image image_ploter(core_shape.get_width(), core_shape.get_height(), _nes_database->_nInstance_list.size()); - - // plot bin - auto bin_grid_shape = _nes_database->_grid_manager->get_shape(); - int32_t bin_cnt_x = _nes_database->_grid_manager->get_grid_cnt_x(); - int32_t bin_cnt_y = _nes_database->_grid_manager->get_grid_cnt_y(); - int32_t bin_width = _nes_database->_grid_manager->get_grid_size_x(); - int32_t bin_height = _nes_database->_grid_manager->get_grid_size_y(); - int32_t bin_grid_x = 0; - int32_t bin_grid_y = 0; - - for (int32_t i = 0; i < bin_cnt_x; i++) { - image_ploter.drawLine(bin_grid_x, bin_grid_y, bin_grid_x, bin_grid_y + bin_grid_shape.get_height(), IMAGE_COLOR::klightGray); - bin_grid_x += bin_width; - } + auto core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); + // auto core_shape = _nes_database->_core_shape; + auto& force_2d_x_list = _nes_database->_density_gradient->get_force_2d_x_list(); + auto& force_2d_y_list = _nes_database->_density_gradient->get_force_2d_y_list(); + + Image image_ploter(core_shape.get_width(), core_shape.get_height(), _nes_database->_nInstance_list.size()); + + // plot bin + auto bin_grid_shape = _nes_database->_grid_manager->get_shape(); + int32_t bin_cnt_x = _nes_database->_grid_manager->get_grid_cnt_x(); + int32_t bin_cnt_y = _nes_database->_grid_manager->get_grid_cnt_y(); + int32_t bin_width = _nes_database->_grid_manager->get_grid_size_x(); + int32_t bin_height = _nes_database->_grid_manager->get_grid_size_y(); + int32_t bin_grid_x = 0; + int32_t bin_grid_y = 0; + + for (int32_t i = 0; i < bin_cnt_x; i++) { image_ploter.drawLine(bin_grid_x, bin_grid_y, bin_grid_x, bin_grid_y + bin_grid_shape.get_height(), IMAGE_COLOR::klightGray); + bin_grid_x += bin_width; + } + image_ploter.drawLine(bin_grid_x, bin_grid_y, bin_grid_x, bin_grid_y + bin_grid_shape.get_height(), IMAGE_COLOR::klightGray); - bin_grid_x = 0; - for (int32_t i = 0; i < bin_cnt_y; i++) { - image_ploter.drawLine(bin_grid_x, bin_grid_y, bin_grid_x + bin_grid_shape.get_width(), bin_grid_y, IMAGE_COLOR::klightGray); - bin_grid_y += bin_height; - } + bin_grid_x = 0; + for (int32_t i = 0; i < bin_cnt_y; i++) { image_ploter.drawLine(bin_grid_x, bin_grid_y, bin_grid_x + bin_grid_shape.get_width(), bin_grid_y, IMAGE_COLOR::klightGray); + bin_grid_y += bin_height; + } + image_ploter.drawLine(bin_grid_x, bin_grid_y, bin_grid_x + bin_grid_shape.get_width(), bin_grid_y, IMAGE_COLOR::klightGray); - float electro_force_max = 0; - int max_len = std::numeric_limits::max(); - for (int i = 0; i < bin_cnt_y; i++) { - for (int j = 0; j < bin_cnt_x; j++) { - electro_force_max = std::max(electro_force_max, std::hypot(force_2d_x_list[i][j], force_2d_y_list[i][j])); - max_len = std::min({ max_len, bin_width, bin_height }); - } + float electro_force_max = 0; + int max_len = std::numeric_limits::max(); + for (int i = 0; i < bin_cnt_y; i++) { + for (int j = 0; j < bin_cnt_x; j++) { + electro_force_max = std::max(electro_force_max, std::hypot(force_2d_x_list[i][j], force_2d_y_list[i][j])); + max_len = std::min({max_len, bin_width, bin_height}); } + } - for (int i = 0; i < bin_cnt_y; i++) { - for (int j = 0; j < bin_cnt_x; j++) { - float fx = force_2d_x_list[i][j]; - float fy = force_2d_y_list[i][j]; - float f = std::hypot(fx, fy); - float ratio = f / electro_force_max; - float dx = fx / f * max_len * ratio; - float dy = fy / f * max_len * ratio; + for (int i = 0; i < bin_cnt_y; i++) { + for (int j = 0; j < bin_cnt_x; j++) { + float fx = force_2d_x_list[i][j]; + float fy = force_2d_y_list[i][j]; + float f = std::hypot(fx, fy); + float ratio = f / electro_force_max; + float dx = fx / f * max_len * ratio; + float dy = fy / f * max_len * ratio; - int cx = j * bin_width + bin_width / 2; - int cy = i * bin_height + bin_height / 2; + int cx = j * bin_width + bin_width / 2; + int cy = i * bin_height + bin_height / 2; - image_ploter.drawArc(cx, cy, cx + dx, cy + dy); - } + image_ploter.drawArc(cx, cy, cx + dx, cy + dy); } - image_ploter.save(iPLAPIInst.obtainTargetDir() + "/pl/plot/" + file_name + ".jpg"); -#endif } + image_ploter.save(iPLAPIInst.obtainTargetDir() + "/pl/plot/" + file_name + ".jpg"); +#endif +} + +void NesterovPlace::printIterInfoToCsv(std::ofstream& file_stream, int32_t iter_num) +{ + file_stream << _nes_database->_wirelength_grad_sum << "," << _nes_database->_density_grad_sum * _nes_database->_density_penalty << "," + << _nes_database->_density_penalty << "," << _nes_database->_nesterov_solver->get_next_steplength() << std::endl; + ; +} - void NesterovPlace::printIterInfoToCsv(std::ofstream& file_stream, int32_t iter_num) - { - file_stream << _nes_database->_wirelength_grad_sum << "," << _nes_database->_density_grad_sum * _nes_database->_density_penalty << "," - << _nes_database->_density_penalty << "," << _nes_database->_nesterov_solver->get_next_steplength() << std::endl; - ; +void NesterovPlace::printDensityMapToCsv(std::string file_name) +{ + std::ofstream file_stream; + file_stream.open(iPLAPIInst.obtainTargetDir() + "/pl/" + file_name + ".csv"); + if (!file_stream.good()) { + LOG_WARNING << "Cannot open file for density map calculation!"; } - void NesterovPlace::printDensityMapToCsv(std::string file_name) - { - std::ofstream file_stream; - file_stream.open(iPLAPIInst.obtainTargetDir() + "/pl/" + file_name + ".csv"); - if (!file_stream.good()) { - LOG_WARNING << "Cannot open file for density map calculation!"; + int32_t grid_cnt_y = _nes_database->_grid_manager->get_grid_cnt_y(); + int32_t grid_cnt_x = _nes_database->_grid_manager->get_grid_cnt_x(); + float available_ratio = _nes_database->_grid_manager->get_available_ratio(); + auto& grid_2d_list = _nes_database->_grid_manager->get_grid_2d_list(); + + for (int32_t i = grid_cnt_y - 1; i >= 0; i--) { + for (int32_t j = 0; j < grid_cnt_x; j++) { + file_stream << grid_2d_list[i][j].obtainGridDensity() / available_ratio << ","; } + file_stream << std::endl; + } - int32_t grid_cnt_y = _nes_database->_grid_manager->get_grid_cnt_y(); - int32_t grid_cnt_x = _nes_database->_grid_manager->get_grid_cnt_x(); - float available_ratio = _nes_database->_grid_manager->get_available_ratio(); - auto& grid_2d_list = _nes_database->_grid_manager->get_grid_2d_list(); + file_stream.close(); +} - for (int32_t i = grid_cnt_y - 1; i >= 0; i--) { - for (int32_t j = 0; j < grid_cnt_x; j++) { - file_stream << grid_2d_list[i][j].obtainGridDensity() / available_ratio << ","; - } - file_stream << std::endl; - } +void NesterovPlace::writeBackPlacerDB() +{ + // #pragma omp parallel for num_threads(_nes_config.get_thread_num()) + for (auto pair : _nes_database->_instance_map) { + auto* n_inst = pair.first; + auto* inst = pair.second; - file_stream.close(); + inst->update_center_coordi(n_inst->get_density_center_coordi()); } + PlacerDBInst.updateGridManager(); +} - void NesterovPlace::writeBackPlacerDB() - { - // #pragma omp parallel for num_threads(_nes_config.get_thread_num()) - for (auto pair : _nes_database->_instance_map) { - auto* n_inst = pair.first; - auto* inst = pair.second; +void NesterovPlace::updateMaxLengthNetWeight() +{ + int32_t max_wirelength_constraint = _nes_config.get_max_net_wirelength(); - inst->update_center_coordi(n_inst->get_density_center_coordi()); + for (auto* n_net : _nes_database->_nNet_list) { + if (n_net->isDontCare()) { + continue; } - PlacerDBInst.updateGridManager(); - } - void NesterovPlace::updateMaxLengthNetWeight() - { - int32_t max_wirelength_constraint = _nes_config.get_max_net_wirelength(); + int32_t n_net_wirelength = _nes_database->_wirelength->obtainNetWirelength(n_net->get_net_id()); + int32_t delta = n_net_wirelength - max_wirelength_constraint; + if (delta < 0) { + continue; + } - for (auto* n_net : _nes_database->_nNet_list) { - if (n_net->isDontCare()) { - continue; - } + float wl_overflow = static_cast(delta) / max_wirelength_constraint; + float pre_delta_weight = n_net->get_delta_weight(); + float cur_delta_weight = static_cast(1 + exp(1)) / (1 + exp(-wl_overflow)) - 1; + float delta_weight = 0.5 * pre_delta_weight + 0.5 * cur_delta_weight; - int32_t n_net_wirelength = _nes_database->_wirelength->obtainNetWirelength(n_net->get_net_id()); - int32_t delta = n_net_wirelength - max_wirelength_constraint; - if (delta < 0) { - continue; - } + n_net->set_weight(n_net->get_weight() + delta_weight); + n_net->set_delta_weight(delta_weight); + } +} + +void NesterovPlace::updateTimingNetWeight() +{ + float cita = 0.2; - float wl_overflow = static_cast(delta) / max_wirelength_constraint; - float pre_delta_weight = n_net->get_delta_weight(); - float cur_delta_weight = static_cast(1 + exp(1)) / (1 + exp(-wl_overflow)) - 1; - float delta_weight = 0.5 * pre_delta_weight + 0.5 * cur_delta_weight; + auto* topo_manager = _nes_database->_topology_manager; + auto* timing_annotation = _nes_database->_timing_annotation; + auto& nNet_list = _nes_database->_nNet_list; + std::vector prev_miu_list; + prev_miu_list.resize(nNet_list.size()); + float prev_max_centrality = timing_annotation->get_max_centrality(); + for (size_t i = 0; i < nNet_list.size(); i++) { + if (Utility().isFloatApproximatelyZero(prev_max_centrality)) { + prev_miu_list[i] = 0.0f; + continue; + } - n_net->set_weight(n_net->get_weight() + delta_weight); - n_net->set_delta_weight(delta_weight); + auto* n_net = nNet_list[i]; + auto* network = topo_manager->findNetworkById(n_net->get_net_id()); + if (n_net->isDontCare()) { + prev_miu_list[i] = 0.0f; + } else { + prev_miu_list[i] = timing_annotation->get_network_centrality(network) / prev_max_centrality; } } - void NesterovPlace::updateTimingNetWeight() - { - float cita = 0.2; + timing_annotation->updateSTATimingFull(); + timing_annotation->updateCriticalityAndCentralityFull(); - auto* topo_manager = _nes_database->_topology_manager; - auto* timing_annotation = _nes_database->_timing_annotation; - auto& nNet_list = _nes_database->_nNet_list; - std::vector prev_miu_list; - prev_miu_list.resize(nNet_list.size()); - float prev_max_centrality = timing_annotation->get_max_centrality(); - for (size_t i = 0; i < nNet_list.size(); i++) { - if (Utility().isFloatApproximatelyZero(prev_max_centrality)) { - prev_miu_list[i] = 0.0f; - continue; - } + float cur_max_centrality = timing_annotation->get_max_centrality(); + for (size_t i = 0; i < nNet_list.size(); i++) { + if (Utility().isFloatApproximatelyZero(cur_max_centrality)) { + break; + } - auto* n_net = nNet_list[i]; - auto* network = topo_manager->findNetworkById(n_net->get_net_id()); - if (n_net->isDontCare()) { - prev_miu_list[i] = 0.0f; - } - else { - prev_miu_list[i] = timing_annotation->get_network_centrality(network) / prev_max_centrality; - } + auto* n_net = nNet_list[i]; + auto* network = topo_manager->findNetworkById(n_net->get_net_id()); + if (n_net->isDontCare()) { + // + } else { + float cur_miu = timing_annotation->get_network_centrality(network) / cur_max_centrality; + float delta_weight = cita * prev_miu_list[i] + (1 - cita) * cur_miu; + float cur_netweight = n_net->get_weight() + delta_weight; + n_net->set_weight(cur_netweight); } + } +} - timing_annotation->updateSTATimingFull(); - timing_annotation->updateCriticalityAndCentralityFull(); +void NesterovPlace::printNesterovDatabase() +{ + int32_t nes_inst_cnt = _nes_database->_nInstance_list.size(); + int32_t fixed_nes_inst_cnt = 0; + int32_t macro_nes_inst_cnt = 0; + int32_t stdcell_nes_inst_cnt = 0; + int32_t filler_nes_inst_cnt = 0; - float cur_max_centrality = timing_annotation->get_max_centrality(); - for (size_t i = 0; i < nNet_list.size(); i++) { - if (Utility().isFloatApproximatelyZero(cur_max_centrality)) { - break; - } + for (auto n_inst : _nes_database->_nInstance_list) { + if (n_inst->isFixed()) { + fixed_nes_inst_cnt++; + } - auto* n_net = nNet_list[i]; - auto* network = topo_manager->findNetworkById(n_net->get_net_id()); - if (n_net->isDontCare()) { - // - } - else { - float cur_miu = timing_annotation->get_network_centrality(network) / cur_max_centrality; - float delta_weight = cita * prev_miu_list[i] + (1 - cita) * cur_miu; - float cur_netweight = n_net->get_weight() + delta_weight; - n_net->set_weight(cur_netweight); + if (n_inst->isMacro()) { + macro_nes_inst_cnt++; + } else { + stdcell_nes_inst_cnt++; + if (n_inst->isFiller()) { + filler_nes_inst_cnt++; } } } - void NesterovPlace::printNesterovDatabase() - { - int32_t nes_inst_cnt = _nes_database->_nInstance_list.size(); - int32_t fixed_nes_inst_cnt = 0; - int32_t macro_nes_inst_cnt = 0; - int32_t stdcell_nes_inst_cnt = 0; - int32_t filler_nes_inst_cnt = 0; + LOG_INFO << "NesInstances Num : " << nes_inst_cnt; + LOG_INFO << "1. Macro Num : " << macro_nes_inst_cnt; + LOG_INFO << "2. Stdcell Num : " << stdcell_nes_inst_cnt; + LOG_INFO << "2.1 Filler Num : " << filler_nes_inst_cnt; + LOG_INFO << "Fixed NesInstances Num : " << fixed_nes_inst_cnt; - for (auto n_inst : _nes_database->_nInstance_list) { - if (n_inst->isFixed()) { - fixed_nes_inst_cnt++; - } + int32_t nes_net_cnt = _nes_database->_nNet_list.size(); + int32_t dont_care_net_cnt = 0; + int32_t set_weight_net_cnt = 0; - if (n_inst->isMacro()) { - macro_nes_inst_cnt++; - } - else { - stdcell_nes_inst_cnt++; - if (n_inst->isFiller()) { - filler_nes_inst_cnt++; - } - } + for (auto n_net : _nes_database->_nNet_list) { + if (n_net->isDontCare()) { + dont_care_net_cnt++; } - LOG_INFO << "NesInstances Num : " << nes_inst_cnt; - LOG_INFO << "1. Macro Num : " << macro_nes_inst_cnt; - LOG_INFO << "2. Stdcell Num : " << stdcell_nes_inst_cnt; - LOG_INFO << "2.1 Filler Num : " << filler_nes_inst_cnt; - LOG_INFO << "Fixed NesInstances Num : " << fixed_nes_inst_cnt; + if (fabs(n_net->get_weight() - 1.0F) >= 1e-5) { + set_weight_net_cnt++; + } + } - int32_t nes_net_cnt = _nes_database->_nNet_list.size(); - int32_t dont_care_net_cnt = 0; - int32_t set_weight_net_cnt = 0; + LOG_INFO << "NesNets Num : " << nes_net_cnt; + LOG_INFO << "Dont Care Num : " << dont_care_net_cnt; + LOG_INFO << "Set NetWeight Num : " << set_weight_net_cnt; - for (auto n_net : _nes_database->_nNet_list) { - if (n_net->isDontCare()) { - dont_care_net_cnt++; - } + LOG_INFO << "NesPins Num : " << _nes_database->_nPin_list.size(); - if (fabs(n_net->get_weight() - 1.0F) >= 1e-5) { - set_weight_net_cnt++; - } - } + int32_t bin_size_x = _nes_database->_grid_manager->get_grid_size_x(); + int32_t bin_size_y = _nes_database->_grid_manager->get_grid_size_y(); + LOG_INFO << "BinGrid Info"; + LOG_INFO << "BinCnt(x * y) : " << _nes_config.get_bin_cnt_x() << " * " << _nes_config.get_bin_cnt_y(); + LOG_INFO << "BinSize(width , height) : " << bin_size_x << " , " << bin_size_y; + LOG_INFO << "Target Density : " << _nes_config.get_target_density(); +} - LOG_INFO << "NesNets Num : " << nes_net_cnt; - LOG_INFO << "Dont Care Num : " << dont_care_net_cnt; - LOG_INFO << "Set NetWeight Num : " << set_weight_net_cnt; +void NesterovPlace::printAcrossLongNet(std::ofstream& long_net_stream, int32_t max_width, int32_t max_height) +{ + auto* topo_manager = _nes_database->_topology_manager; + auto core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); + int32_t core_width = core_shape.get_width(); + int32_t core_height = core_shape.get_height(); - LOG_INFO << "NesPins Num : " << _nes_database->_nPin_list.size(); + int net_count = 0; - int32_t bin_size_x = _nes_database->_grid_manager->get_grid_size_x(); - int32_t bin_size_y = _nes_database->_grid_manager->get_grid_size_y(); - LOG_INFO << "BinGrid Info"; - LOG_INFO << "BinCnt(x * y) : " << _nes_config.get_bin_cnt_x() << " * " << _nes_config.get_bin_cnt_y(); - LOG_INFO << "BinSize(width , height) : " << bin_size_x << " , " << bin_size_y; - LOG_INFO << "Target Density : " << _nes_config.get_target_density(); + for (auto* network : topo_manager->get_network_list()) { + auto shape = network->obtainNetWorkShape(); + int32_t network_width = shape.get_width(); + int32_t network_height = shape.get_height(); + + if (network_width > max_width && network_height > max_height) { + long_net_stream << "Net : " << network->get_name() << " Width/CoreWidth " << network_width << "/" << core_width + << " Height/CoreHeight " << network_height << "/" << core_height << std::endl; + ++net_count; + } else if (network_width > max_width) { + long_net_stream << "Net : " << network->get_name() << " Width/CoreWidth " << network_width << "/" << core_width << std::endl; + ++net_count; + } else if (network_height > max_height) { + long_net_stream << "Net : " << network->get_name() << " Height/CoreHeight " << network_height << "/" << core_height << std::endl; + ++net_count; + } } - void NesterovPlace::printAcrossLongNet(std::ofstream& long_net_stream, int32_t max_width, int32_t max_height) - { - auto* topo_manager = _nes_database->_topology_manager; - auto core_shape = _nes_database->_placer_db->get_layout()->get_core_shape(); - int32_t core_width = core_shape.get_width(); - int32_t core_height = core_shape.get_height(); + long_net_stream << std::endl; + long_net_stream << "SUMMARY : " + << "AcrossLongNets / Total Nets = " << net_count << " / " << topo_manager->get_network_list().size() << std::endl; + long_net_stream << std::endl << std::endl; +} - int net_count = 0; +void NesterovPlace::saveNesterovPlaceData(int32_t cur_iter) +{ + iplf::plInst->clearFileInstanceList(); - for (auto* network : topo_manager->get_network_list()) { - auto shape = network->obtainNetWorkShape(); - int32_t network_width = shape.get_width(); - int32_t network_height = shape.get_height(); + for (auto pair : _nes_database->_instance_map) { + auto* nes_inst = pair.first; - if (network_width > max_width && network_height > max_height) { - long_net_stream << "Net : " << network->get_name() << " Width/CoreWidth " << network_width << "/" << core_width - << " Height/CoreHeight " << network_height << "/" << core_height << std::endl; - ++net_count; - } - else if (network_width > max_width) { - long_net_stream << "Net : " << network->get_name() << " Width/CoreWidth " << network_width << "/" << core_width << std::endl; - ++net_count; - } - else if (network_height > max_height) { - long_net_stream << "Net : " << network->get_name() << " Height/CoreHeight " << network_height << "/" << core_height << std::endl; - ++net_count; - } + if (nes_inst->isFiller()) { + continue; } - long_net_stream << std::endl; - long_net_stream << "SUMMARY : " - << "AcrossLongNets / Total Nets = " << net_count << " / " << topo_manager->get_network_list().size() << std::endl; - long_net_stream << std::endl << std::endl; - } + auto* inst = pair.second; + int32_t coordi_x = nes_inst->get_density_center_coordi().get_x() - inst->get_shape_width() / 2; + int32_t coordi_y = nes_inst->get_density_center_coordi().get_y() - inst->get_shape_height() / 2; - void NesterovPlace::saveNesterovPlaceData(int32_t cur_iter) - { - iplf::plInst->clearFileInstanceList(); + std::string orient; + if (inst->get_orient() == Orient::kN_R0) { + orient = "N_R0"; + } else if (inst->get_orient() == Orient::kS_R180) { + orient = "S_R180"; + } else if (inst->get_orient() == Orient::kFN_MY) { + orient = "FN_MY"; + } else if (inst->get_orient() == Orient::kFS_MX) { + orient = "FS_MX"; + } - for (auto pair : _nes_database->_instance_map) { - auto* nes_inst = pair.first; + iplf::plInst->addFileInstance(nes_inst->get_name(), coordi_x, coordi_y, (int8_t) inst->get_orient()); + } - if (nes_inst->isFiller()) { - continue; - } + iplf::plInst->saveInstanceDataToDirectory(iPLAPIInst.obtainTargetDir() + "/pl/gui/"); +} - auto* inst = pair.second; - int32_t coordi_x = nes_inst->get_density_center_coordi().get_x() - inst->get_shape_width() / 2; - int32_t coordi_y = nes_inst->get_density_center_coordi().get_y() - inst->get_shape_height() / 2; +void NesterovPlace::printIterationCoordi(std::ofstream& long_net_stream, int32_t cur_iter) +{ + for (auto pair : _nes_database->_instance_map) { + auto* nes_inst = pair.first; - std::string orient; - if (inst->get_orient() == Orient::kN_R0) { - orient = "N_R0"; - } - else if (inst->get_orient() == Orient::kS_R180) { - orient = "S_R180"; - } - else if (inst->get_orient() == Orient::kFN_MY) { - orient = "FN_MY"; - } - else if (inst->get_orient() == Orient::kFS_MX) { - orient = "FS_MX"; - } - - iplf::plInst->addFileInstance(nes_inst->get_name(), coordi_x, coordi_y, (int8_t)inst->get_orient()); + if (nes_inst->isFiller()) { + continue; } - iplf::plInst->saveInstanceDataToDirectory(iPLAPIInst.obtainTargetDir() + "/pl/gui/"); - } + auto* inst = pair.second; + int32_t coordi_x = nes_inst->get_density_center_coordi().get_x() - inst->get_shape_width() / 2; + int32_t coordi_y = nes_inst->get_density_center_coordi().get_y() - inst->get_shape_height() / 2; - void NesterovPlace::printIterationCoordi(std::ofstream& long_net_stream, int32_t cur_iter) - { - for (auto pair : _nes_database->_instance_map) { - auto* nes_inst = pair.first; + std::string orient; + if (inst->get_orient() == Orient::kN_R0) { + orient = "N_R0"; + } else if (inst->get_orient() == Orient::kS_R180) { + orient = "S_R180"; + } else if (inst->get_orient() == Orient::kFN_MY) { + orient = "FN_MY"; + } else if (inst->get_orient() == Orient::kFS_MX) { + orient = "FS_MX"; + } - if (nes_inst->isFiller()) { - continue; - } + long_net_stream << nes_inst->get_name() << " " << coordi_x << "," << coordi_y << " " << orient << std::endl; + } +} + +void NesterovPlace::resetOverflowRecordList() +{ + _overflow_record_list.clear(); +} - auto* inst = pair.second; - int32_t coordi_x = nes_inst->get_density_center_coordi().get_x() - inst->get_shape_width() / 2; - int32_t coordi_y = nes_inst->get_density_center_coordi().get_y() - inst->get_shape_height() / 2; +void NesterovPlace::resetHPWLRecordList() +{ + _hpwl_record_list.clear(); +} - std::string orient; - if (inst->get_orient() == Orient::kN_R0) { - orient = "N_R0"; - } - else if (inst->get_orient() == Orient::kS_R180) { - orient = "S_R180"; - } - else if (inst->get_orient() == Orient::kFN_MY) { - orient = "FN_MY"; - } - else if (inst->get_orient() == Orient::kFS_MX) { - orient = "FS_MX"; - } +void NesterovPlace::initQuadPenaltyCoeff() +{ + int64_t cur_overflow = std::max((int64_t) 1, _nes_database->_bin_grid->get_overflow_area_without_filler()); - long_net_stream << nes_inst->get_name() << " " << coordi_x << "," << coordi_y << " " << orient << std::endl; - } - } + // density weight subgradient preconditioner + float density_weight_grad_precond = 1.0 / cur_overflow; + _quad_penalty_coeff = _quad_penalty_coeff / 2 * density_weight_grad_precond; +} - void NesterovPlace::resetOverflowRecordList() - { - _overflow_record_list.clear(); +bool NesterovPlace::checkPlateau(int32_t window, float threshold) +{ + int32_t cur_size = static_cast(_overflow_record_list.size()); + if (cur_size < window) { + return false; } - void NesterovPlace::resetHPWLRecordList() - { - _hpwl_record_list.clear(); + float max = FLT_MIN; + float min = FLT_MAX; + float avg = 0.0; + auto iter_end = _overflow_record_list.rbegin() + window; + for (auto it = _overflow_record_list.rbegin(); it != iter_end; it++) { + *it > max ? max = *it : max; + *it < min ? min = *it : min; + avg += *it; } - void NesterovPlace::initQuadPenaltyCoeff() - { - int64_t cur_overflow = std::max((int64_t)1, _nes_database->_bin_grid->get_overflow_area_without_filler()); + return (max - min) / (avg / window) < threshold; +} - // density weight subgradient preconditioner - float density_weight_grad_precond = 1.0 / cur_overflow; - _quad_penalty_coeff = _quad_penalty_coeff / 2 * density_weight_grad_precond; +void NesterovPlace::entropyInjection(float shrink_factor, float noise_intensity) +{ + int64_t center_x = 0; + int64_t center_y = 0; + int32_t movable_inst_cnt = 0; + // cal all movable instance mean center + for (auto* inst : _nes_database->_nInstance_list) { + if (inst->isFixed()) { + continue; + } + auto inst_center = std::move(inst->get_density_center_coordi()); + center_x += inst_center.get_x(); + center_y += inst_center.get_y(); + movable_inst_cnt++; } - bool NesterovPlace::checkPlateau(int32_t window, float threshold) - { - int32_t cur_size = static_cast(_overflow_record_list.size()); - if (cur_size < window) { - return false; - } + center_x /= movable_inst_cnt; + center_y /= movable_inst_cnt; - float max = FLT_MIN; - float min = FLT_MAX; - float avg = 0.0; - auto iter_end = _overflow_record_list.rbegin() + window; - for (auto it = _overflow_record_list.rbegin(); it != iter_end; it++) { - *it > max ? max = *it : max; - *it < min ? min = *it : min; - avg += *it; + int32_t seed = 1000; + std::default_random_engine gen(seed); + std::normal_distribution dis(0, 1); + for (auto* inst : _nes_database->_nInstance_list) { + if (inst->isFixed()) { + continue; } + auto inst_center = std::move(inst->get_density_center_coordi()); - return (max - min) / (avg / window) < threshold; - } + // shrink all movable insts + int32_t new_x = (inst_center.get_x() - center_x) * shrink_factor + center_x; + int32_t new_y = (inst_center.get_y() - center_y) * shrink_factor + center_y; - void NesterovPlace::entropyInjection(float shrink_factor, float noise_intensity) - { - int64_t center_x = 0; - int64_t center_y = 0; - int32_t movable_inst_cnt = 0; - // cal all movable instance mean center - for (auto* inst : _nes_database->_nInstance_list) { - if (inst->isFixed()) { - continue; - } - auto inst_center = std::move(inst->get_density_center_coordi()); - center_x += inst_center.get_x(); - center_y += inst_center.get_y(); - movable_inst_cnt++; - } + // add some noise + new_x += noise_intensity * dis(gen); + new_y += noise_intensity * dis(gen); - center_x /= movable_inst_cnt; - center_y /= movable_inst_cnt; - - int32_t seed = 1000; - std::default_random_engine gen(seed); - std::normal_distribution dis(0, 1); - for (auto* inst : _nes_database->_nInstance_list) { - if (inst->isFixed()) { - continue; - } - auto inst_center = std::move(inst->get_density_center_coordi()); + inst->updateDensityCenterLocation(new_x, new_y); + } +} - // shrink all movable insts - int32_t new_x = (inst_center.get_x() - center_x) * shrink_factor + center_x; - int32_t new_y = (inst_center.get_y() - center_y) * shrink_factor + center_y; +bool NesterovPlace::checkDivergence(int32_t window, float threshold, bool is_routability) +{ + if (static_cast(_overflow_record_list.size()) < window) { + return false; + } - // add some noise - new_x += noise_intensity * dis(gen); - new_y += noise_intensity * dis(gen); + int32_t begin_idx = static_cast(_overflow_record_list.size() - window); + int32_t end_idx = static_cast(_overflow_record_list.size()); - inst->updateDensityCenterLocation(new_x, new_y); - } - } + float overflow_mean = 0.0f; + float overflow_diff = 0.0f; + float overflow_max = FLT_MIN; + float overflow_min = FLT_MAX; + int64_t wl_mean = 0; + float wl_ratio, overflow_ratio; - bool NesterovPlace::checkDivergence(int32_t window, float threshold, bool is_routability) - { - if (static_cast(_overflow_record_list.size()) < window) { - return false; + for (int32_t i = begin_idx; i < end_idx; i++) { + float overflow = _overflow_record_list[i]; + overflow_mean += overflow; + if (i + 1 < end_idx) { + overflow_diff += std::fabs(_overflow_record_list[i + 1] - overflow); } + overflow > overflow_max ? overflow_max = overflow : overflow; + overflow < overflow_min ? overflow_min = overflow : overflow; - int32_t begin_idx = static_cast(_overflow_record_list.size() - window); - int32_t end_idx = static_cast(_overflow_record_list.size()); - - float overflow_mean = 0.0f; - float overflow_diff = 0.0f; - float overflow_max = FLT_MIN; - float overflow_min = FLT_MAX; - int64_t wl_mean = 0; - float wl_ratio, overflow_ratio; - - for (int32_t i = begin_idx; i < end_idx; i++) { - float overflow = _overflow_record_list[i]; - overflow_mean += overflow; - if (i + 1 < end_idx) { - overflow_diff += std::fabs(_overflow_record_list[i + 1] - overflow); - } - overflow > overflow_max ? overflow_max = overflow : overflow; - overflow < overflow_min ? overflow_min = overflow : overflow; + wl_mean += _hpwl_record_list[i]; + } + overflow_mean /= window; + overflow_diff /= window; + wl_mean /= window; + overflow_ratio = (overflow_mean - std::max(_nes_config.get_target_overflow(), _best_overflow)) / _best_overflow; + wl_ratio = static_cast(wl_mean - _best_hpwl) / _best_hpwl; - wl_mean += _hpwl_record_list[i]; - } - overflow_mean /= window; - overflow_diff /= window; - wl_mean /= window; - overflow_ratio = (overflow_mean - std::max(_nes_config.get_target_overflow(), _best_overflow)) / _best_overflow; - wl_ratio = static_cast(wl_mean - _best_hpwl) / _best_hpwl; - - if (wl_ratio > threshold * 1.2) { - if (overflow_ratio > threshold && is_routability == false) { - LOG_WARNING << "Detect divergence: overflow increases too much than best overflow (" << overflow_ratio << " > " << threshold << ")"; - return true; - } - else if ((overflow_max - overflow_min) / overflow_mean < threshold && is_routability == false) { - LOG_WARNING << "Detect divergence: overflow plateau ( " << (overflow_max - overflow_min) / overflow_mean << " < " << threshold - << ")"; - return true; - } - else if (overflow_diff > 0.6) { - LOG_WARNING << "Detect divergence: overflow fluctuate too frequently (" << overflow_diff << "> 0.6)"; - return true; - } - else { - return false; - } - } - else { + if (wl_ratio > threshold * 1.2) { + if (overflow_ratio > threshold && is_routability == false) { + LOG_WARNING << "Detect divergence: overflow increases too much than best overflow (" << overflow_ratio << " > " << threshold << ")"; + return true; + } else if ((overflow_max - overflow_min) / overflow_mean < threshold && is_routability == false) { + LOG_WARNING << "Detect divergence: overflow plateau ( " << (overflow_max - overflow_min) / overflow_mean << " < " << threshold << ")"; + return true; + } else if (overflow_diff > 0.6) { + LOG_WARNING << "Detect divergence: overflow fluctuate too frequently (" << overflow_diff << "> 0.6)"; + return true; + } else { return false; } + } else { + return false; } +} - bool NesterovPlace::checkLongTimeOverflowUnchanged(int32_t window, float threshold) - { - if (static_cast(_overflow_record_list.size()) < window) { - return false; - } +bool NesterovPlace::checkLongTimeOverflowUnchanged(int32_t window, float threshold) +{ + if (static_cast(_overflow_record_list.size()) < window) { + return false; + } - int32_t begin_idx = static_cast(_overflow_record_list.size() - window); - int32_t end_idx = static_cast(_overflow_record_list.size()); + int32_t begin_idx = static_cast(_overflow_record_list.size() - window); + int32_t end_idx = static_cast(_overflow_record_list.size()); - float overflow_mean = 0.0f; - float overflow_max = FLT_MIN; - float overflow_min = FLT_MAX; + float overflow_mean = 0.0f; + float overflow_max = FLT_MIN; + float overflow_min = FLT_MAX; - for (int32_t i = begin_idx; i < end_idx; i++) { - float overflow = _overflow_record_list[i]; - overflow_mean += overflow; - overflow > overflow_max ? overflow_max = overflow : overflow; - overflow < overflow_min ? overflow_min = overflow : overflow; - } + for (int32_t i = begin_idx; i < end_idx; i++) { + float overflow = _overflow_record_list[i]; + overflow_mean += overflow; + overflow > overflow_max ? overflow_max = overflow : overflow; + overflow < overflow_min ? overflow_min = overflow : overflow; + } - overflow_mean /= window; + overflow_mean /= window; - float overflow_ratio = (overflow_max - overflow_min) / overflow_mean; - if (overflow_ratio < 0.8 * threshold) { - LOG_WARNING << "Detect divergence: overflow plateau ( " << overflow_ratio << " < " << (0.8 * threshold) << ")"; - return true; - } - else { - return false; - } + float overflow_ratio = (overflow_max - overflow_min) / overflow_mean; + if (overflow_ratio < 0.8 * threshold) { + LOG_WARNING << "Detect divergence: overflow plateau ( " << overflow_ratio << " < " << (0.8 * threshold) << ")"; + return true; + } else { + return false; } +} } // namespace ipl diff --git a/src/operation/iPNP/CMakeLists.txt b/src/operation/iPNP/CMakeLists.txt index 242b4aa367108d728aca4dea67b89957876e6435..b8f308a6e32a1a4be19825c43a59e51037f8a3df 100644 --- a/src/operation/iPNP/CMakeLists.txt +++ b/src/operation/iPNP/CMakeLists.txt @@ -1,38 +1,43 @@ cmake_minimum_required(VERSION 3.0) -project(iPNP) set (CMAKE_CXX_STANDARD 20) -include_directories(${HOME_DATABASE}/manager) -include_directories(${HOME_PLATFORM}/data_manager) -include_directories(${HOME_EVALUATION}) -include_directories(${HOME_EVALUATION}/api) - -set(IPNP_PROJECT_SOURCE_DIR ${HOME_OPERATION}/iPNP) - -include_directories(${IPNP_PROJECT_SOURCE_DIR}/source) - -include_directories(${IPNP_PROJECT_SOURCE_DIR}/api) -include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/config) -include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/include) -include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/data_manager) -include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/module/evaluator) -include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/module/optimizer) -include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/module/router) -include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/module/synthesis) -include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/module) -include_directories(SYSTEM ${HOME_THIRDPARTY}) - -include(${HOME_CMAKE}/operation/idb.cmake) -include(${HOME_CMAKE}/operation/irt.cmake) -include(${HOME_CMAKE}/operation/iplf.cmake) - -link_directories(${CMAKE_BINARY_DIR}/lib) - add_subdirectory(api) -# add_subdirectory(data) add_subdirectory(source) -add_subdirectory(test) -add_executable(iPNP main.cpp) +include_directories(${HOME_DATABASE}/manager) + include_directories(${HOME_PLATFORM}/data_manager) + include_directories(${HOME_EVALUATION}) + include_directories(${HOME_EVALUATION}/api) + + set(IPNP_PROJECT_SOURCE_DIR ${HOME_OPERATION}/iPNP) + + include_directories(${IPNP_PROJECT_SOURCE_DIR}/source) + + include_directories(${IPNP_PROJECT_SOURCE_DIR}/api) + include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/config) + include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/include) + include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/data_manager) + + include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/module/evaluator) + include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/module/optimizer) + include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/module/router) + include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/module/synthesis) + include_directories(${IPNP_PROJECT_SOURCE_DIR}/source/module) + include_directories(SYSTEM ${HOME_THIRDPARTY}) + + include(${HOME_CMAKE}/operation/idb.cmake) + include(${HOME_CMAKE}/operation/irt.cmake) + include(${HOME_CMAKE}/operation/iplf.cmake) + + link_directories(${CMAKE_BINARY_DIR}/lib) + +option(BUILD_PNP_EXECUTE "Build PNP exe OFF" OFF) + +if(BUILD_PNP_EXECUTE) + project(iPNP) + + add_executable(iPNP main.cpp) + + target_link_libraries(iPNP pnp ipnp_api pnp-config) +endif() -target_link_libraries(iPNP pnp iPNPApi) diff --git a/src/operation/iPNP/README.md b/src/operation/iPNP/README.md index e402335020cacb6c7940a2b5f619facd89ae29d9..3cb3947b30572d1a89b659456d8c795185c5fba6 100644 --- a/src/operation/iPNP/README.md +++ b/src/operation/iPNP/README.md @@ -1,283 +1,183 @@ -# iPNP 使用指南 +# iPNP: Power Network Planning -## 概述 +## Overview -iPNP是一个平衡拥塞和电压降的芯片电源网络布局工具,基于模拟退火算法实现,它支持电源网络生成、IR降分析和拥塞评估等功能。 +iPNP is a chip power network layout tool that balances congestion and IR drop, powered by a simulated annealing algorithm. It supports functionalities including power network generation, IR drop analysis, and congestion evaluation. -![输入图片说明](docs/iPNP%20introduction.png)## 目前支持的功能 +![Input Image Description](docs/iPNP%20introduction.png) -1. 读入 def/lef 文件,构建 idb_builder,在 builder 中添加电源线和通孔,输出结果 def 文件 +## Supported Features -2. 对芯片版图进行划分,每个区域都可以分配不同的电源模板,即可控制每个区域的电源线密度 +1. **Design File Processing**: Reads DEF/LEF files to construct an IDB builder, adds power rails/vias, and exports DEF files. +2. **Region Partitioning**: Divides the chip layout into regions with customizable power templates to control rail density. +3. **Power Routing**: Implements power rails and vias across layers based on predefined templates. +4. **Pre-layout Acceleration**: Integrates with iPL tool for rapid initial placement. +5. **Congestion Evaluation**: Uses EGR tool to calculate overflow per layer. +6. **IR Drop Analysis**: Employs IR evaluation tool to compute voltage drop for each instance. +7. **Optimization Engine**: Utilizes simulated annealing to iteratively minimize overflow and IR drop scores. -3. 按照设定好的模板,对每层的每个区域打上电源线,层与层之间打上通孔,实现电源的连通 +--- -4. 可调用 iPL 工具,先完成快速布局,为后续评估拥塞和 IR drop 做准备 +## Installation -5. 可调用 EGR 工具,计算出当前电源网络下,每一层的 overflow +iPNP is located in the `src/operation/iPNP/` directory. After compilation, the executable resides in `bin/`. -6. 可调用 IR evaluation 工具,计算出到每个 instance 的 IR drop +--- -7. 以模拟退火算法为核心,经过多次迭代,找到关于 overflow 和 IR drop 的 best score +## Usage - +### Configuration File Preparation -## 安装 +Create a JSON-formatted configuration file (e.g., `pnp_config.json`) containing all runtime parameters. -iPNP工具位于 `src/operation/iPNP/` 目录下。编译完成后,可执行文件将位于 `bin/` 目录中。 +### Running iPNP +Multiple execution modes are supported: - -## 使用方法 - -### 编写配置文件 - -首先需要创建一个JSON格式的配置文件,例如 `pnp_config.json`。配置文件包含了iPNP运行所需的所有参数。 - -### 运行iPNP - -有几种运行iPNP的方式: - -**命令行模式**: - +**Command Line Mode**: ```bash cd bin/ ./iPNP -c /path/to/pnp_config.json ``` -**指定输出文件**: - +**Specify Output File**: ```bash ./iPNP -c /path/to/pnp_config.json -o /path/to/output.def ``` -**交互式模式**: - +**Interactive Mode**: ```bash ./iPNP -i ``` -**运行TCL脚本**: - +**Run TCL Script**: ```bash ./iPNP -s /path/to/script.tcl ``` -**帮助:** - +**Help Menu**: ```bash ./iPNP -h ``` -![输入图片说明](docs/iPNP_help.png) - -### TCL命令 +![Help Menu Screenshot](docs/iPNP_help.png) -运行完整的iPNP流程: +### TCL Commands +Use the following command in interactive mode: ```tcl run_pnp -config /path/to/pnp_config.json ``` -在VIA1上添加通孔,即连接M2和M1层。根据VIA2的通孔位置,在相同坐标下添加VIA1的通孔,确保电源网络可以完全连通到M1层。 +--- -(注意:这个tcl命令不会运行完整的iPNP流程,只用于通孔没达到M1上的数据集) - -```tcl -add_via1 -config /path/to/pnp_config.json -``` +## Configuration File Details +The JSON configuration file comprises the following sections: -## 配置文件详解 - -配置文件采用JSON格式,包含以下主要部分: - -### design - 设计文件信息 +### Design Specifications ```json "design": { - "lef_files": ["文件1.lef", "文件2.lef", ...], // LEF技术和单元库文件 - "def_file": "设计.def", // 输入DEF文件 - "output_def_file": "输出.def", // 输出DEF文件路径 - "sdc_file": "时序.sdc" // SDC时序约束文件 + "lef_files": ["file1.lef", "file2.lef"], // Technology/library files + "def_file": "input.def", // Input DEF file + "output_def_file": "output.def", // Output DEF path + "sdc_file": "timing.sdc" // Timing constraints } ``` -### lib - 库文件信息 +### Library Files ```json "lib": { - "liberty_files": ["文件1.lib", "文件2.lib", ...] // liberty库文件列表 + "liberty_files": ["lib1.lib", "lib2.lib"] // Liberty library list } ``` -### timing - 时序分析设置 +### Timing Analysis ```json "timing": { - "design_workspace": "/path/to/workspace" // ir drop结果输出目录 + "design_workspace": "/path/to/workspace" // IR drop output directory } ``` -### power - 电源网络设置 +### Power Network ```json "power": { - "power_net_name": "VDD" // 电源网络名称 + "power_net_name": "VDD" // Power net identifier } ``` -### egr - 拥塞评估相关 +### Congestion Evaluation ```json "egr": { - "map_path": "/path/to/map" // 拥塞图输出路径 + "map_path": "/path/to/map" // Congestion map output path } ``` -### grid - 电源网格设置 +### Grid Configuration ```json "grid": { - "power_layers": [9, 8, 7, 6, 5, 4, 3], // 电源层列表,从高到低排列 - "ho_region_num": 2, // 水平区域数量 - "ver_region_num": 2 // 垂直区域数量 + "power_layer": [9, 8, 7, 6, 5, 4, 3], // Power layers (high to low) + "ho_region_num": 2, // Horizontal regions + "ver_region_num": 2 // Vertical regions } ``` -### templates - 电源网格模板设置 +### Power Templates ```json "templates": { - "horizontal": [ // 水平方向模板 + "horizontal": [ // Horizontal rail templates { - "width": 8000.0, // 电源线宽度 - "pg_offset": 1600.0, // VDD和VSS的间距 - "space": 19200.0, // 两条VDD之间的距离 - "offset": 8000.0 // 第一条VDD距离die底部/左侧的距离 - }, - // 更多水平模板... + "width": 8000.0, // Rail width + "pg_offset": 1600.0, // VDD/VSS spacing + "space": 19200.0, // Inter-rail spacing + "offset": 8000.0 // Offset from die edge + } ], - "vertical": [ // 垂直方向模板 + "vertical": [ // Vertical rail templates { "width": 8000.0, "pg_offset": 1600.0, "space": 19200.0, "offset": 8000.0 - }, - // 更多垂直模板... + } ] } ``` -![输入图片说明](docs/template_info.png)### simulated_annealing - 模拟退火算法参数 +![Template Configuration Example](docs/template_info.png) +### Simulated Annealing Parameters ```json "simulated_annealing": { - "initial_temp": 100.0, // 初始温度 - "cooling_rate": 0.95, // 冷却率 - "min_temp": 0.1, // 最小温度 - "iterations_per_temp": 10, // 每个温度的迭代次数 - "ir_drop_weight": 0.6, // IR drop权重 - "overflow_weight": 0.4, // 拥塞权重 - "modifiable_layer_min": 3, // 模拟退火可替换模板的最底层 - "modifiable_layer_max": 6 // 模拟退火可替换模板的最高层 + "initial_temp": 100.0, // Initial temperature + "cooling_rate": 0.95, // Cooling rate + "min_temp": 0.1, // Minimum temperature + "iterations_per_temp": 10, // Iterations per temperature + "ir_drop_weight": 0.6, // IR drop weight + "overflow_weight": 0.4, // Overflow weight + "modifiable_layer_min": 3, // Adjustable layer range (min) + "modifiable_layer_max": 6 // Adjustable layer range (max) } ``` +--- - -## 配置示例 - -以下是一个完整的配置文件示例: +## Configuration Example ```json { "design": { - "lef_files": [ - "/home/sujianrong/T28/tlef/tsmcn28_9lm6X2ZUTRDL.tlef", - "/home/sujianrong/T28/lef/PLLTS28HPMLAINT.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140opplvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140lvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140uhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140hvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140oppuhvt.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta256x32m4fw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140cg.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140oppuhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140mbhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140ulvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140uhvt.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta64x100m2fw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140hvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140oppulvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140mb.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140cgcwhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140lvt.lef", - "/home/sujianrong/T28/lef/tpbn28v_9lm.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta64x128m2f_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140uhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140mblvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140cgcw.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140mbhvt.lef", - "/home/sujianrong/T28/lef/tpbn28v.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta64x128m2fw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140lvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140ulvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140opphvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140cgehvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140mb.lef", - "/home/sujianrong/T28/lef/tphn28hpcpgv18_9lm.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta64x88m2fw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140mb.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140cghvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140opp.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140cghvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140oppehvt.lef", - "/home/sujianrong/T28/lef/ts1n28hpcplvtb2048x48m8sw_180a.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta64x92m2fw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140mblvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140cg.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140opplvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140cg.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140opphvt.lef", - "/home/sujianrong/T28/lef/ts1n28hpcplvtb512x128m4sw_180a.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta64x96m2fw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140opphvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140hvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140oppuhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140cguhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140opp.lef", - "/home/sujianrong/T28/lef/ts1n28hpcplvtb512x64m4sw_180a.lef", - "/home/sujianrong/T28/lef/ts6n28hpcplvta2048x32m8sw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140opp.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140oppulvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140ehvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140opplvt.lef", - "/home/sujianrong/T28/lef/ts1n28hpcplvtb8192x64m8sw_180a.lef" - ], - "def_file": "/home/sujianrong/iEDA/src/operation/iPNP/data/test/aes_no_pwr.def", - "output_def_file": "/home/sujianrong/iEDA/src/operation/iPNP/data/test/output.def", - "sdc_file": "/home/sujianrong/aes/aes.sdc" - }, - "lib": { - "liberty_files": [ - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp40p140ssg0p81v125c.lib", - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp40p140hvtssg0p81v125c.lib", - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp35p140ssg0p81v125c.lib", - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp35p140lvtssg0p81v125c.lib", - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp40p140lvtssg0p81v125c.lib", - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp30p140lvtssg0p81v125c.lib", - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp30p140ssg0p81v125c.lib" - ] - }, - "timing": { - "design_workspace": "/home/sujianrong/iEDA/src/operation/iPNP/data/ir/ir_temp_directory" - }, - "power": { - "power_net_name": "VDD" - }, - "egr":{ - "map_path":"/home/sujianrong/iEDA/src/operation/iPNP/data" + "lef_files": [...], // List of LEF files + "def_file": "input.def", + "output_def_file": "output.def", + "sdc_file": "timing.sdc" }, + "lib": { "liberty_files": [...] }, + "timing": { "design_workspace": "/path/to/ir_results" }, + "power": { "power_net_name": "VDD" }, + "egr": { "map_path": "/path/to/congestion_maps" }, "grid": { - "power_layers": [9,8,7,6,5,4,3], + "power_layer": [9,8,7,6,5,4,3], "ho_region_num": 2, "ver_region_num": 2 }, @@ -291,7 +191,7 @@ add_via1 -config /path/to/pnp_config.json "modifiable_layer_min": 3, "modifiable_layer_max": 6 }, - "templates":{ + "templates": { "horizontal": [ { "width": 8000.0, @@ -333,23 +233,22 @@ add_via1 -config /path/to/pnp_config.json } ] } -} +} ``` +--- +## Output Files -## 输出结果 - -运行完成后,iPNP会生成以下文件: - -1. 带有电源网格的DEF文件(在配置的`output_def_file`路径) -2. IR drop分析报告 -3. 拥塞评估结果 - +Upon completion, iPNP generates: +1. DEF file with power grid (`output_def_file`) +2. IR drop analysis report +3. Congestion evaluation results +--- -## 注意事项 +## Notes -1. 确保所有文件路径正确且文件存在 -2. 电源层列表按从高到低的顺序排列 -3. 模板中的参数已经乘了dbu +1. Verify all file paths exist and are accessible. +2. Power layers must be listed from highest to lowest. +3. Template parameters are specified in database units (DBU). \ No newline at end of file diff --git a/src/operation/iPNP/api/CMakeLists.txt b/src/operation/iPNP/api/CMakeLists.txt index e09cf5585749de93279c56d21aad87637aa13e3c..c3cae90f3ca22d96c8208d5c96200e531b91c4d5 100644 --- a/src/operation/iPNP/api/CMakeLists.txt +++ b/src/operation/iPNP/api/CMakeLists.txt @@ -1,13 +1,13 @@ -add_library(iPNPApi -iPNPApi.cpp +add_library(ipnp_api +ipnp_api.cpp ) -target_link_libraries(iPNPApi +target_link_libraries(ipnp_api PUBLIC pnp ) -target_include_directories(iPNPApi +target_include_directories(ipnp_api PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/src/operation/iPNP/api/ipnp_api.cpp b/src/operation/iPNP/api/ipnp_api.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cdfe128816dc46b5f8e7afa2ac49c5c6e19057a8 --- /dev/null +++ b/src/operation/iPNP/api/ipnp_api.cpp @@ -0,0 +1,51 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file ipnp_api.hh + * @author Jianrong Su + * @brief + * @version 1.0 + * @date 2025-06-23 + */ + +#include "ipnp_api.hh" + +#include "PNP.hh" +#include "log/Log.hh" + +namespace ipnp { + +PNPApi* PNPApi::_instance = nullptr; + +void PNPApi::run_pnp(std::string config) +{ + auto pnp = PNP(config); + // run + pnp.init(); + pnp.runSynthesis(); + pnp.saveToIdb(); +} + +void PNPApi::connect_M2_M1(std::string config) +{ + auto pnp = PNP(config); + pnp.init(); + pnp.connect_M2_M1(); + pnp.saveToIdb(); +} + +} // namespace ipnp \ No newline at end of file diff --git a/src/operation/iPNP/api/ipnp_api.hh b/src/operation/iPNP/api/ipnp_api.hh new file mode 100644 index 0000000000000000000000000000000000000000..a4e8d1ec25bd16b745a0be1f1e7eab0e8ce3e048 --- /dev/null +++ b/src/operation/iPNP/api/ipnp_api.hh @@ -0,0 +1,66 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file ipnp_api.hh + * @author Jianrong Su + * @brief + * @version 1.0 + * @date 2025-06-23 + */ + +#ifndef IPNP_API_HH +#define IPNP_API_HH + +#pragma once +#include +#include +#include + +#include "log/Log.hh" + +namespace idb { +class IdbBuilder; +} + +#define PNPApiInst (ipnp::PNPApi::getInstance()) + +namespace ipnp { + +class iPNP; + +class PNPApi +{ + public: + static PNPApi* getInstance() + { + if (_instance == nullptr) { + _instance = new PNPApi(); + } + + return _instance; + } + + static void run_pnp(std::string config); + static void connect_M2_M1(std::string config); + + private: + static PNPApi* _instance; +}; + +} // namespace ipnp + +#endif // IPNP_API_HH \ No newline at end of file diff --git a/src/operation/iPNP/example/pnp_config.json b/src/operation/iPNP/example/pnp_config.json index 68c0b53cc44365488743654684d8523d5e7d5059..978484e4f78f8e7abf4fffa1b69a0e38e8fd0f15 100644 --- a/src/operation/iPNP/example/pnp_config.json +++ b/src/operation/iPNP/example/pnp_config.json @@ -1,69 +1,7 @@ { "design": { "lef_files": [ - "/home/sujianrong/T28/tlef/tsmcn28_9lm6X2ZUTRDL.tlef", - "/home/sujianrong/T28/lef/PLLTS28HPMLAINT.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140opplvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140lvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140uhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140hvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140oppuhvt.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta256x32m4fw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140cg.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140oppuhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140mbhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140ulvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140uhvt.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta64x100m2fw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140hvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140oppulvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140mb.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140cgcwhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140lvt.lef", - "/home/sujianrong/T28/lef/tpbn28v_9lm.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta64x128m2f_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140uhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140mblvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140cgcw.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140mbhvt.lef", - "/home/sujianrong/T28/lef/tpbn28v.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta64x128m2fw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140lvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140ulvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140opphvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140cgehvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140mb.lef", - "/home/sujianrong/T28/lef/tphn28hpcpgv18_9lm.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta64x88m2fw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140mb.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140cghvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140opp.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140cghvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140oppehvt.lef", - "/home/sujianrong/T28/lef/ts1n28hpcplvtb2048x48m8sw_180a.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta64x92m2fw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140mblvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140cg.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140opplvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140cg.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140opphvt.lef", - "/home/sujianrong/T28/lef/ts1n28hpcplvtb512x128m4sw_180a.lef", - "/home/sujianrong/T28/lef/ts5n28hpcplvta64x96m2fw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140opphvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140hvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140oppuhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140cguhvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140opp.lef", - "/home/sujianrong/T28/lef/ts1n28hpcplvtb512x64m4sw_180a.lef", - "/home/sujianrong/T28/lef/ts6n28hpcplvta2048x32m8sw_130a.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp30p140opp.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp35p140oppulvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140ehvt.lef", - "/home/sujianrong/T28/lef/tcbn28hpcplusbwp40p140opplvt.lef", - "/home/sujianrong/T28/lef/ts1n28hpcplvtb8192x64m8sw_180a.lef" + ], "def_file": "/home/sujianrong/iEDA/src/operation/iPNP/data/test/aes_no_pwr.def", "output_def_file": "/home/sujianrong/iEDA/src/operation/iPNP/example/result/output.def", @@ -71,23 +9,17 @@ }, "lib": { "liberty_files": [ - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp40p140ssg0p81v125c.lib", - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp40p140hvtssg0p81v125c.lib", - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp35p140ssg0p81v125c.lib", - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp35p140lvtssg0p81v125c.lib", - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp40p140lvtssg0p81v125c.lib", - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp30p140lvtssg0p81v125c.lib", - "/home/sujianrong/T28/lib/tcbn28hpcplusbwp30p140ssg0p81v125c.lib" + ] }, "timing": { - "design_workspace": "/home/sujianrong/iEDA/src/operation/iPNP/example/result/ir" + "design_workspace": "/home/taosimin/iEDA24/iEDA/src/operation/iPNP/test" }, "power": { "power_net_name": "VDD" }, "egr":{ - "map_path":"/home/sujianrong/iEDA/src/operation/iPNP/example/result" + "map_path":"/home/taosimin/iEDA24/iEDA/src/operation/iPNP/test" }, "grid": { "power_layers": [9,8,7,6,5,4,3], diff --git a/src/operation/iPNP/main.cpp b/src/operation/iPNP/main.cpp index 1674e2a78eb6158499760a4acfc3597c5984e023..5fb1a80d41b8649a5e9d3c96304ca9cb2f5765ee 100644 --- a/src/operation/iPNP/main.cpp +++ b/src/operation/iPNP/main.cpp @@ -22,58 +22,58 @@ * @date 2025-07-01 */ -#include -#include +#include #include #include +#include #include +#include -#include "iPNP.hh" -#include "iPNPApi.hh" -#include "log/Log.hh" -#include "cxxopts.hpp" +#include "PNP.hh" #include "PNPConfig.hh" -#include +#include "PNPShellCmd.hh" +#include "cxxopts.hpp" +#include "ipnp_api.hh" +#include "log/Log.hh" #include "tcl/UserShell.hh" -#include "tcl-cmd/ShellCmd.hh" using namespace idb; using namespace ipnp; -int registerCommands() { - registerTclCmd(CmdRunPnp, "run_pnp"); - registerTclCmd(CmdAddVIA1, "add_via1"); +int registerCommands() +{ + registerTclCmd(ipnp::CmdRunPnp, "run_pnp"); + registerTclCmd(ipnp::CmdAddVIA1, "add_via1"); return EXIT_SUCCESS; } -int main(int argc, char** argv) { - - std::string hello_info = - "\033[49;32m***************************\n" - " _ ____ _ ______ \n" - " (_) __ \\/ | / / __ \\ \n" - " / / /_/ / |/ / /_/ / \n" - " / / ____/ /| / ____/ \n" - "/_/_/ /_/ |_/_/ \n" - " \n" - "***************************\n" - "WELCOME TO iPNP interface. \e[0m"; +int main(int argc, char** argv) +{ + Log::init(argv, "/home/sujianrong/iEDA/src/operation/iPNP/example/result/log_info/"); + + std::string hello_info + = "\033[49;32m***************************\n" + " _ ____ _ ______ \n" + " (_) __ \\/ | / / __ \\ \n" + " / / /_/ / |/ / /_/ / \n" + " / / ____/ /| / ____/ \n" + "/_/_/ /_/ |_/_/ \n" + " \n" + "***************************\n" + "WELCOME TO iPNP interface. \e[0m"; std::cout << hello_info << std::endl; auto shell = ieda::UserShell::getShell(); - + shell->set_init_func(registerCommands); cxxopts::Options options("iPNP", "iPNP command line help."); - options.add_options() - ("c,config", "JSON configuration file", cxxopts::value()) - ("o,output", "Output DEF file path", cxxopts::value()) - ("i,interactive", "Run in interactive TCL shell mode", cxxopts::value()->default_value("false")) - ("s,script", "TCL script file to run", cxxopts::value()) - ("v,version", "Print version") - ("h,help", "Print help"); + options.add_options()("c,config", "JSON configuration file", cxxopts::value())( + "o,output", "Output DEF file path", cxxopts::value())("i,interactive", "Run in interactive TCL shell mode", + cxxopts::value()->default_value("false"))( + "s,script", "TCL script file to run", cxxopts::value())("v,version", "Print version")("h,help", "Print help"); try { auto result = options.parse(argc, argv); @@ -90,7 +90,7 @@ int main(int argc, char** argv) { // Check if running in interactive mode bool interactive_mode = result["interactive"].as(); - + // Check if running script file bool script_mode = result.count("script"); std::string script_file; @@ -110,8 +110,7 @@ int main(int argc, char** argv) { auto tcl_argc = argc - 1; auto tcl_argv = argv + 1; shell->userMain(tcl_argc, tcl_argv); - } - else { + } else { // Get configuration file path std::string config_file_path; if (result.count("config")) { @@ -127,39 +126,31 @@ int main(int argc, char** argv) { return 1; } - // Create iPNP instance - ipnp::iPNP ipnp(config_file_path); - ipnp::iPNPApi::setInstance(&ipnp); + LOG_INFO << "Running iPNP with configuration: " << config_file_path; - // Override output DEF file path from command line (if provided) - if (result.count("output")) { - ipnp.set_output_def_path(result["output"].as()); - } - - std::string start_info = - "\033[49;32m" - " _ ____ _ ______ ______________ ____ ______\n" - " (_) __ \\/ | / / __ \\ / ___/_ __/ | / __ \\/_ __/\n" - " / / /_/ / |/ / /_/ / \\__ \\ / / / /| | / /_/ / / / \n" - " / / ____/ /| / ____/ ___/ // / / ___ |/ _, _/ / / \n" - "/_/_/ /_/ |_/_/ /____//_/ /_/ |_/_/ |_| /_/ \n" - " \n" - "\e[0m"; + std::string start_info + = "\033[49;32m" + " _ ____ _ ______ ______________ ____ ______\n" + " (_) __ \\/ | / / __ \\ / ___/_ __/ | / __ \\/_ __/\n" + " / / /_/ / |/ / /_/ / \\__ \\ / / / /| | / /_/ / / / \n" + " / / ____/ /| / ____/ ___/ // / / ___ |/ _, _/ / / \n" + "/_/_/ /_/ |_/_/ /____//_/ /_/ |_/_/ |_| /_/ \n" + " \n" + "\e[0m"; std::cout << start_info << std::endl; - // Run iPNP - ipnp.run(); - - std::string finish_info = - "\033[49;32m" - " _ ____ _ ______ ___________ ___________ __ __\n" - " (_) __ \\/ | / / __ \\ / ____/ _/ | / / _/ ___// / / /\n" - " / / /_/ / |/ / /_/ / / /_ / // |/ // / \\__ \\/ /_/ / \n" - " / / ____/ /| / ____/ / __/ _/ // /| // / ___/ / __ / \n" - "/_/_/ /_/ |_/_/ /_/ /___/_/ |_/___//____/_/ /_/ \n" - " \n" - "\e[0m"; + ipnp::PNPApi::run_pnp(config_file_path); + + std::string finish_info + = "\033[49;32m" + " _ ____ _ ______ ___________ ___________ __ __\n" + " (_) __ \\/ | / / __ \\ / ____/ _/ | / / _/ ___// / / /\n" + " / / /_/ / |/ / /_/ / / /_ / // |/ // / \\__ \\/ /_/ / \n" + " / / ____/ /| / ____/ / __/ _/ // /| // / ___/ / __ / \n" + "/_/_/ /_/ |_/_/ /_/ /___/_/ |_/___//____/_/ /_/ \n" + " \n" + "\e[0m"; std::cout << finish_info << std::endl; } @@ -172,5 +163,7 @@ int main(int argc, char** argv) { return 1; } + Log::end(); + return 0; } diff --git a/src/operation/iPNP/source/CMakeLists.txt b/src/operation/iPNP/source/CMakeLists.txt index 6a4b38c936d15f80263912da4d2809496bb9b3d3..18469ab398114fc4c995da0d8c665708602306bc 100644 --- a/src/operation/iPNP/source/CMakeLists.txt +++ b/src/operation/iPNP/source/CMakeLists.txt @@ -2,22 +2,28 @@ add_subdirectory(config) add_subdirectory(data_manager) add_subdirectory(module) -add_library(pnp iPNP.cpp) +add_library(pnp PNP.cpp) + +target_link_libraries(pnp + pnp-evaluator + pnp-optimizer + pnp-synthesis + pnp-data + pnp-config -target_link_libraries( - pnp - pnp-cmd - optimizer - evaluator - synthesis - data_manager - config - idb - tcl log usage pthread stdc++fs - IdbBuilder - def_service - lef_service) +) + +if(BUILD_PNP_EXECUTE) + target_link_libraries(pnp + pnp-cmd +) +endif() + +target_include_directories(pnp + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/src/operation/iPNP/source/PNP.cpp b/src/operation/iPNP/source/PNP.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a6a82c9a6cf9fd38b69ae1dd5ad74f9899249749 --- /dev/null +++ b/src/operation/iPNP/source/PNP.cpp @@ -0,0 +1,221 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file PNP.cpp + * @author Jianrong Su + * @brief + * @version 1.0 + * @date 2025-06-23 + */ + +#include "PNP.hh" + +#include +#include +#include +#include + +#include +#include + +#include "CongestionEval.hh" +#include "FastPlacer.hh" +#include "IREval.hh" +#include "NetworkSynthesis.hh" +#include "PNPConfig.hh" +#include "PNPIdbWrapper.hh" +#include "PdnOptimizer.hh" +#include "idm.h" +#include "log/Log.hh" + +namespace ipnp { + +PNP::PNP() +{ +} + +PNP::PNP(const std::string& config_file) +{ + if (!pnpConfig->loadConfigFromJson(config_file)) { + LOG_WARNING << "Initializing PNP with default configuration" << std::endl; + } +} + +void PNP::runSynthesis() +{ + NetworkSynthesis network_synthesizer(SysnType::kDefault, _input_network); + network_synthesizer.synthesizeNetwork(); + _initialized_network = network_synthesizer.get_network(); + _current_opt_network = _initialized_network; +} + +void PNP::runOptimize() +{ + saveToIdb(); + PdnOptimizer pdn_optimizer; + + pdn_optimizer.optimizeGlobal(_initialized_network); + _current_opt_network = pdn_optimizer.get_out_put_grid(); +} + +void PNP::runFastPlacer() +{ + FastPlacer fast_placer; + fast_placer.runFastPlacer(); +} + +void PNP::init() +{ + // Initialize the input network + _input_network = PNPGridManager(); + + _input_network.set_power_layers(pnpConfig->get_power_layers()); + _input_network.set_ho_region_num(pnpConfig->get_ho_region_num()); + _input_network.set_ver_region_num(pnpConfig->get_ver_region_num()); + + _input_network.set_layer_count(_input_network.get_power_layers().size()); + _input_network.set_die_width(dmInst->get_idb_layout()->get_die()->get_width()); + _input_network.set_die_height(dmInst->get_idb_layout()->get_die()->get_height()); + + // Initialize with configuration-based templates if available + _input_network.init_PNPGridManager_data(); +} + +void PNP::initIRAnalysis() +{ + static bool is_init = false; + if (!is_init) { + // Initialize IREval + _ir_eval.initIREval(); + is_init = true; + } +} + +void PNP::runAnalysis() +{ + saveToIdb(); + + CongestionEval cong_eval; + + cong_eval.evalEGR(); + + _ir_eval.runIREval(); + + // Get analysis results + double max_ir_drop = _ir_eval.getMaxIRDrop(); + double min_ir_drop = _ir_eval.getMinIRDrop(); + double avg_ir_drop = _ir_eval.getAvgIRDrop(); + int32_t overflow = cong_eval.get_total_overflow_union(); + + // Build final_report path + std::string final_report_path = "final_report.txt"; + if (!pnpConfig->get_report_path().empty()) { + std::string dir_path = pnpConfig->get_report_path(); + if (dir_path.back() != '/') { + dir_path += '/'; + } + final_report_path = dir_path + "final_report.txt"; + LOG_INFO << "Using directory from config for final report: " << dir_path << std::endl; + } + + LOG_INFO << "Final report will be written to: " << final_report_path << std::endl; + + std::string directory = final_report_path.substr(0, final_report_path.find_last_of('/')); + if (!directory.empty()) { + auto create_directories = [](const std::string& path) -> bool { + size_t pos = 0; + std::string dir; + int ret = 0; + if (path[0] == '/') { + pos = 1; + } + + while ((pos = path.find('/', pos)) != std::string::npos) { + dir = path.substr(0, pos++); + if (dir.empty()) + continue; + + ret = mkdir(dir.c_str(), 0755); + if (ret != 0 && errno != EEXIST) { + return false; + } + } + return true; + }; + + if (!create_directories(directory)) { + LOG_ERROR << "Failed to create directory: " << directory << ", error: " << strerror(errno) << std::endl; + } else { + LOG_INFO << "Directory ensured: " << directory << std::endl; + } + } + + // Open file for writing + std::ofstream report_file(final_report_path.c_str(), std::ios::out | std::ios::trunc); + if (!report_file.is_open()) { + LOG_ERROR << "Failed to open final report file for writing: " << final_report_path << std::endl; + } else { + LOG_INFO << "Successfully opened final report file for writing" << std::endl; + + report_file << std::fixed << std::setprecision(6); + + report_file << "======================================================================" << std::endl; + report_file << " FINAL POWER NETWORK ANALYSIS REPORT " << std::endl; + report_file << "======================================================================" << std::endl; + report_file << std::endl; + + report_file << "IR DROP ANALYSIS:" << std::endl; + report_file << " Maximum IR Drop : " << std::setw(12) << max_ir_drop << std::endl; + report_file << " Minimum IR Drop : " << std::setw(12) << min_ir_drop << std::endl; + report_file << " Average IR Drop : " << std::setw(12) << avg_ir_drop << std::endl; + report_file << std::endl; + + report_file << "CONGESTION ANALYSIS:" << std::endl; + report_file << " Total Overflow : " << std::setw(12) << overflow << std::endl; + report_file << std::endl; + + report_file << "----------------------------------------------------------------------" << std::endl; + + report_file.close(); + LOG_INFO << "Final analysis report written successfully" << std::endl; + } +} + +void PNP::connect_M2_M1() +{ + _idb_wrapper.connect_M2_M1_Layer(); +} + +void PNP::run() +{ + // initializing + init(); + initIRAnalysis(); + + // running + runSynthesis(); + runFastPlacer(); + runOptimize(); + runAnalysis(); +} + +void PNP::writeIdbToDef(std::string def_path) +{ + dmInst->saveDef(def_path); +} + +} // namespace ipnp diff --git a/src/operation/iPNP/source/PNP.hh b/src/operation/iPNP/source/PNP.hh new file mode 100644 index 0000000000000000000000000000000000000000..d7b89e1c172a6f11deb465dc0deab42de4e97631 --- /dev/null +++ b/src/operation/iPNP/source/PNP.hh @@ -0,0 +1,77 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file PNP.hh + * @author Xinhao li + * @brief Top level file of PNP module. + * @version 0.1 + * @date 2024-07-15 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "IREval.hh" +#include "PNPGridManager.hh" +#include "PNPIdbWrapper.hh" + +namespace ipnp { + +class PNP +{ + public: + PNP(); + PNP(const std::string& config_file); + ~PNP() = default; + + PNPGridManager get_initialized_network() { return _initialized_network; } + PNPGridManager get_current_opt_network() { return _current_opt_network; } + + void init(); + void initIRAnalysis(); + void runSynthesis(); + void runOptimize(); // including calling Evaluator and modify PDN + void runFastPlacer(); + void saveToIdb() { _idb_wrapper.saveToIdb(_current_opt_network); } + void writeIdbToDef(std::string def_path); + void runAnalysis(); + + void connect_M2_M1(); + + void run(); // According to the config. e.g. which Evaluator, which opt algorithm. + + // Set the output DEF file path + void set_output_def_path(const std::string& path) { _output_def_path = path; } + + private: + PNPGridManager _input_network; + PNPGridManager _initialized_network; + PNPGridManager _current_opt_network; + + PNPIdbWrapper _idb_wrapper; + IREval _ir_eval; + + std::string _output_def_path; +}; + +} // namespace ipnp diff --git a/src/operation/iPNP/source/config/CMakeLists.txt b/src/operation/iPNP/source/config/CMakeLists.txt index 5f83083a9cbf08d39f40f8da968bf107bebe2fb6..e821eb38b291279b3bfc1b9232636b89b220d673 100644 --- a/src/operation/iPNP/source/config/CMakeLists.txt +++ b/src/operation/iPNP/source/config/CMakeLists.txt @@ -1,2 +1,14 @@ -add_library(config PNPConfig.cpp) -target_link_libraries(config) \ No newline at end of file +add_library(pnp-config PNPConfig.cpp) + +target_link_libraries(pnp-config + PUBLIC + idb + idm +) + +target_include_directories(pnp-config + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +set(CMAKE_BUILD_TYPE "debug") \ No newline at end of file diff --git a/src/operation/iPNP/source/config/PNPConfig.cpp b/src/operation/iPNP/source/config/PNPConfig.cpp index af7b10797a4476cb20cbfa21a43c0eba96b53dcf..16bb15c3fcfce9d68ac53b21c20ca25956a18fde 100644 --- a/src/operation/iPNP/source/config/PNPConfig.cpp +++ b/src/operation/iPNP/source/config/PNPConfig.cpp @@ -23,18 +23,19 @@ */ #include "PNPConfig.hh" -#include "log/Log.hh" + #include + +#include "idm.h" #include "json.hpp" +#include "log/Log.hh" namespace ipnp { -bool loadConfigFromJson(const std::string& config_file_path, PNPConfig* config) { - if (!config) { - LOG_ERROR << "PNPConfig pointer is null!" << std::endl; - return false; - } +PNPConfig* PNPConfig::_instance = nullptr; +bool PNPConfig::loadConfigFromJson(const std::string& config_file_path) +{ if (config_file_path.empty()) { LOG_WARNING << "Config file path is empty, using default configuration." << std::endl; return false; @@ -47,58 +48,60 @@ bool loadConfigFromJson(const std::string& config_file_path, PNPConfig* config) return false; } + auto idb_layers = dmInst->get_idb_layout()->get_layers(); + nlohmann::json json_data; file >> json_data; if (json_data.contains("design")) { auto& design = json_data["design"]; - + if (design.contains("lef_files") && design["lef_files"].is_array()) { std::vector lef_files; for (const auto& lef : design["lef_files"]) { lef_files.push_back(lef.get()); } - config->set_lef_files(lef_files); + set_lef_files(lef_files); } if (design.contains("def_file") && design["def_file"].is_string()) { - config->set_def_path(design["def_file"].get()); + set_def_path(design["def_file"].get()); } if (design.contains("output_def_file") && design["output_def_file"].is_string()) { - config->set_output_def_path(design["output_def_file"].get()); + set_output_def_path(design["output_def_file"].get()); } - + if (design.contains("sdc_file") && design["sdc_file"].is_string()) { - config->set_sdc_file(design["sdc_file"].get()); + set_sdc_file(design["sdc_file"].get()); } } if (json_data.contains("lib")) { auto& lib = json_data["lib"]; - + if (lib.contains("liberty_files") && lib["liberty_files"].is_array()) { std::vector liberty_files; for (const auto& liberty : lib["liberty_files"]) { liberty_files.push_back(liberty.get()); } - config->set_liberty_files(liberty_files); + set_liberty_files(liberty_files); } } if (json_data.contains("timing")) { auto& timing = json_data["timing"]; - + if (timing.contains("design_workspace") && timing["design_workspace"].is_string()) { - config->set_timing_design_workspace(timing["design_workspace"].get()); + set_timing_design_workspace(timing["design_workspace"].get()); } } if (json_data.contains("power")) { auto& power = json_data["power"]; - + if (power.contains("power_net_name") && power["power_net_name"].is_string()) { - config->set_power_net_name(power["power_net_name"].get()); + set_power_net_name(power["power_net_name"].get()); } } @@ -106,124 +109,193 @@ bool loadConfigFromJson(const std::string& config_file_path, PNPConfig* config) auto& egr = json_data["egr"]; if (egr.contains("map_path") && egr["map_path"].is_string()) { - config->set_egr_map_path(egr["map_path"].get()); + set_egr_map_path(egr["map_path"].get()); } } + // Load report path if exists + if (json_data.contains("report_path") && json_data["report_path"].is_string()) { + set_report_path(json_data["report_path"].get()); + } + + if (json_data.contains("pl_default_config_path") && json_data["pl_default_config_path"].is_string()) { + set_pl_default_config_path(json_data["pl_default_config_path"].get()); + } + if (json_data.contains("grid")) { auto& grid = json_data["grid"]; - + if (grid.contains("power_layers") && grid["power_layers"].is_array()) { std::vector power_layers; for (const auto& layer : grid["power_layers"]) { - power_layers.push_back(layer.get()); + std::string layer_tr = layer.get(); + auto idb_layer = idb_layers->find_layer(layer_tr); + + power_layers.push_back(idb_layer->get_id()); } - config->set_power_layers(power_layers); + set_power_layers(power_layers); } if (grid.contains("ho_region_num") && grid["ho_region_num"].is_number()) { - config->set_ho_region_num(grid["ho_region_num"].get()); + set_ho_region_num(grid["ho_region_num"].get()); } if (grid.contains("ver_region_num") && grid["ver_region_num"].is_number()) { - config->set_ver_region_num(grid["ver_region_num"].get()); + set_ver_region_num(grid["ver_region_num"].get()); + } + + if (grid.contains("follow_pin_layers") && grid["follow_pin_layers"].is_array()) { + std::vector follow_pin_layers; + for (const auto& layer : grid["follow_pin_layers"]) { + std::string layer_tr = layer.get(); + auto idb_layer = idb_layers->find_layer(layer_tr); + follow_pin_layers.push_back(idb_layer->get_id()); + } + set_follow_pin_layers(follow_pin_layers); + } + + if (grid.contains("power_port_layer") && grid["power_port_layer"].is_string()) { + std::string layer_tr = grid["power_port_layer"].get(); + auto idb_layer = idb_layers->find_layer(layer_tr); + set_power_port_layer(idb_layer->get_id()); + } + + if (grid.contains("follow_pin_width") && grid["follow_pin_width"].is_number()) { + set_follow_pin_width(grid["follow_pin_width"].get()); } } // Load template configurations if (json_data.contains("templates")) { auto& templates = json_data["templates"]; - + // Load horizontal templates if (templates.contains("horizontal") && templates["horizontal"].is_array()) { std::vector horizontal_templates; for (const auto& template_data : templates["horizontal"]) { TemplateConfig template_config; template_config.direction = "horizontal"; - + if (template_data.contains("width") && template_data["width"].is_number()) { template_config.width = template_data["width"].get(); } - + if (template_data.contains("pg_offset") && template_data["pg_offset"].is_number()) { template_config.pg_offset = template_data["pg_offset"].get(); } - + if (template_data.contains("space") && template_data["space"].is_number()) { template_config.space = template_data["space"].get(); } - + if (template_data.contains("offset") && template_data["offset"].is_number()) { template_config.offset = template_data["offset"].get(); } - + horizontal_templates.push_back(template_config); } - config->set_horizontal_templates(horizontal_templates); + set_horizontal_templates(horizontal_templates); } - + // Load vertical templates if (templates.contains("vertical") && templates["vertical"].is_array()) { std::vector vertical_templates; for (const auto& template_data : templates["vertical"]) { TemplateConfig template_config; template_config.direction = "vertical"; - + if (template_data.contains("width") && template_data["width"].is_number()) { template_config.width = template_data["width"].get(); } - + if (template_data.contains("pg_offset") && template_data["pg_offset"].is_number()) { template_config.pg_offset = template_data["pg_offset"].get(); } - + if (template_data.contains("space") && template_data["space"].is_number()) { template_config.space = template_data["space"].get(); } - + if (template_data.contains("offset") && template_data["offset"].is_number()) { template_config.offset = template_data["offset"].get(); } - + vertical_templates.push_back(template_config); } - config->set_vertical_templates(vertical_templates); + set_vertical_templates(vertical_templates); + } + + // Load layer-specific templates + if (templates.contains("layer_specific") && templates["layer_specific"].is_object()) { + std::map layer_specific_templates; + for (auto& [layer_name, template_data] : templates["layer_specific"].items()) { + TemplateConfig template_config; + + if (template_data.contains("direction") && template_data["direction"].is_string()) { + template_config.direction = template_data["direction"].get(); + } + + if (template_data.contains("width") && template_data["width"].is_number()) { + template_config.width = template_data["width"].get(); + } + + if (template_data.contains("pg_offset") && template_data["pg_offset"].is_number()) { + template_config.pg_offset = template_data["pg_offset"].get(); + } + + if (template_data.contains("space") && template_data["space"].is_number()) { + template_config.space = template_data["space"].get(); + } + + if (template_data.contains("offset") && template_data["offset"].is_number()) { + template_config.offset = template_data["offset"].get(); + } + + layer_specific_templates[layer_name] = template_config; + } + set_layer_specific_templates(layer_specific_templates); } } if (json_data.contains("simulated_annealing")) { auto& sa = json_data["simulated_annealing"]; - + if (sa.contains("initial_temp") && sa["initial_temp"].is_number()) { - config->set_sa_initial_temp(sa["initial_temp"].get()); + set_sa_initial_temp(sa["initial_temp"].get()); } - + if (sa.contains("cooling_rate") && sa["cooling_rate"].is_number()) { - config->set_sa_cooling_rate(sa["cooling_rate"].get()); + set_sa_cooling_rate(sa["cooling_rate"].get()); } - + if (sa.contains("min_temp") && sa["min_temp"].is_number()) { - config->set_sa_min_temp(sa["min_temp"].get()); + set_sa_min_temp(sa["min_temp"].get()); } - + if (sa.contains("iterations_per_temp") && sa["iterations_per_temp"].is_number()) { - config->set_sa_iterations_per_temp(sa["iterations_per_temp"].get()); + set_sa_iterations_per_temp(sa["iterations_per_temp"].get()); } - + if (sa.contains("ir_drop_weight") && sa["ir_drop_weight"].is_number()) { - config->set_sa_ir_drop_weight(sa["ir_drop_weight"].get()); + set_sa_ir_drop_weight(sa["ir_drop_weight"].get()); } - + if (sa.contains("overflow_weight") && sa["overflow_weight"].is_number()) { - config->set_sa_overflow_weight(sa["overflow_weight"].get()); + set_sa_overflow_weight(sa["overflow_weight"].get()); } - + if (sa.contains("modifiable_layer_min") && sa["modifiable_layer_min"].is_number()) { - config->set_sa_modifiable_layer_min(sa["modifiable_layer_min"].get()); + std::string layer_tr = sa["modifiable_layer_min"].get(); + auto idb_layer = idb_layers->find_layer(layer_tr); + + set_sa_modifiable_layer_min(idb_layer->get_id()); } - - if (sa.contains("modifiable_layer_max") && sa["modifiable_layer_max"].is_number()) { - config->set_sa_modifiable_layer_max(sa["modifiable_layer_max"].get()); + + if (sa.contains("modifiable_layer_max")) { + std::string layer_tr = sa["modifiable_layer_max"].get(); + auto idb_layer = idb_layers->find_layer(layer_tr); + + set_sa_modifiable_layer_max(idb_layer->get_id()); } } diff --git a/src/operation/iPNP/source/config/PNPConfig.hh b/src/operation/iPNP/source/config/PNPConfig.hh index 6554105286587e5154393ccb8862b81685671c23..7d41b023908fb7b918e46e4a681f1ebb8da10dc4 100644 --- a/src/operation/iPNP/source/config/PNPConfig.hh +++ b/src/operation/iPNP/source/config/PNPConfig.hh @@ -26,129 +26,171 @@ #include #include +#include #include #include namespace ipnp { - // Template configuration structure - struct TemplateConfig { - std::string direction; - double width; - double pg_offset; - double space; - double offset; - }; +#define pnpConfig (PNPConfig::getInstance()) + +// Template configuration structure +struct TemplateConfig +{ + std::string direction; + double width; + double pg_offset; + double space; + double offset; +}; + +class PNPConfig +{ + public: + static PNPConfig* getInstance() + { + if (!_instance) { + _instance = new PNPConfig(); + } + return _instance; + } - class PNPConfig + static void destroyInst() { - public: - PNPConfig() = default; - ~PNPConfig() = default; - - void set_lef_files(const std::vector& lef_files) { _lef_files = lef_files; } - const std::vector& get_lef_files() const { return _lef_files; } + if (_instance != nullptr) { + delete _instance; + _instance = nullptr; + } + } + + bool loadConfigFromJson(const std::string& config_file_path); + + void set_lef_files(const std::vector& lef_files) { _lef_files = lef_files; } + const std::vector& get_lef_files() const { return _lef_files; } + + void set_def_path(const std::string& def_path) { _def_path = def_path; } + const std::string& get_def_path() const { return _def_path; } + + void set_output_def_path(const std::string& output_def_path) { _output_def_path = output_def_path; } + const std::string& get_output_def_path() const { return _output_def_path; } + + void set_sdc_file(const std::string& sdc_file) { _sdc_file = sdc_file; } + const std::string& get_sdc_file() const { return _sdc_file; } + + void set_power_layers(const std::vector& power_layers) { _power_layers = power_layers; } + const std::vector& get_power_layers() const { return _power_layers; } + + void set_ho_region_num(int ho_region_num) { _ho_region_num = ho_region_num; } + int get_ho_region_num() const { return _ho_region_num; } + + void set_ver_region_num(int ver_region_num) { _ver_region_num = ver_region_num; } + int get_ver_region_num() const { return _ver_region_num; } + + void set_follow_pin_layers(const std::vector& follow_pin_layers) { _follow_pin_layers = follow_pin_layers; } + const std::vector& get_follow_pin_layers() const { return _follow_pin_layers; } + + void set_power_port_layer(int power_port_layer) { _power_port_layer = power_port_layer; } + int get_power_port_layer() const { return _power_port_layer; } + + void set_follow_pin_width(double follow_pin_width) { _follow_pin_width = follow_pin_width; } + double get_follow_pin_width() const { return _follow_pin_width; } + + void set_liberty_files(const std::vector& liberty_files) { _liberty_files = liberty_files; } + const std::vector& get_liberty_files() const { return _liberty_files; } + + void set_timing_design_workspace(const std::string& workspace) { _timing_design_workspace = workspace; } + const std::string& get_timing_design_workspace() const { return _timing_design_workspace; } + + void set_power_net_name(const std::string& name) { _power_net_name = name; } + const std::string& get_power_net_name() const { return _power_net_name; } + + void set_egr_map_path(const std::string& egr_map_path) { _egr_map_path = egr_map_path; } + const std::string& get_egr_map_path() const { return _egr_map_path; } + + void set_pl_default_config_path(const std::string& pl_default_config_path) { _pl_default_config_path = pl_default_config_path; } + const std::string& get_pl_default_config_path() const { return _pl_default_config_path; } + + void set_report_path(const std::string& report_path) { _report_path = report_path; } + const std::string& get_report_path() const { return _report_path; } + + void set_sa_initial_temp(double initial_temp) { _sa_initial_temp = initial_temp; } + double get_sa_initial_temp() const { return _sa_initial_temp; } + + void set_sa_cooling_rate(double cooling_rate) { _sa_cooling_rate = cooling_rate; } + double get_sa_cooling_rate() const { return _sa_cooling_rate; } + + void set_sa_min_temp(double min_temp) { _sa_min_temp = min_temp; } + double get_sa_min_temp() const { return _sa_min_temp; } + + void set_sa_iterations_per_temp(int iterations) { _sa_iterations_per_temp = iterations; } + int get_sa_iterations_per_temp() const { return _sa_iterations_per_temp; } + + void set_sa_ir_drop_weight(double weight) { _sa_ir_drop_weight = weight; } + double get_sa_ir_drop_weight() const { return _sa_ir_drop_weight; } + + void set_sa_overflow_weight(double weight) { _sa_overflow_weight = weight; } + double get_sa_overflow_weight() const { return _sa_overflow_weight; } + + // Range of modifiable layers for simulated annealing algorithm + void set_sa_modifiable_layer_min(int layer) { _sa_modifiable_layer_min = layer; } + int get_sa_modifiable_layer_min() const { return _sa_modifiable_layer_min; } + + void set_sa_modifiable_layer_max(int layer) { _sa_modifiable_layer_max = layer; } + int get_sa_modifiable_layer_max() const { return _sa_modifiable_layer_max; } + + // Template configuration methods + void set_horizontal_templates(const std::vector& templates) { _horizontal_templates = templates; } + const std::vector& get_horizontal_templates() const { return _horizontal_templates; } + + void set_vertical_templates(const std::vector& templates) { _vertical_templates = templates; } + const std::vector& get_vertical_templates() const { return _vertical_templates; } + + void set_layer_specific_templates(const std::map& templates) { _layer_specific_templates = templates; } + const std::map& get_layer_specific_templates() const { return _layer_specific_templates; } + + private: + static PNPConfig* _instance; + + PNPConfig() = default; + ~PNPConfig() = default; + + // design info + std::vector _lef_files; + std::string _def_path; + std::string _output_def_path; + std::string _sdc_file; + + // lib info + std::vector _liberty_files; + + // grid info + std::vector _power_layers; + int _ho_region_num; + int _ver_region_num; + std::vector _follow_pin_layers; + int _power_port_layer; + double _follow_pin_width; - void set_def_path(const std::string& def_path) { _def_path = def_path; } - const std::string& get_def_path() const { return _def_path; } - - void set_output_def_path(const std::string& output_def_path) { _output_def_path = output_def_path; } - const std::string& get_output_def_path() const { return _output_def_path; } - - void set_sdc_file(const std::string& sdc_file) { _sdc_file = sdc_file; } - const std::string& get_sdc_file() const { return _sdc_file; } - - void set_power_layers(const std::vector& power_layers) { _power_layers = power_layers; } - const std::vector& get_power_layers() const { return _power_layers; } - - void set_ho_region_num(int ho_region_num) { _ho_region_num = ho_region_num; } - int get_ho_region_num() const { return _ho_region_num; } - - void set_ver_region_num(int ver_region_num) { _ver_region_num = ver_region_num; } - int get_ver_region_num() const { return _ver_region_num; } - - void set_liberty_files(const std::vector& liberty_files) { _liberty_files = liberty_files; } - const std::vector& get_liberty_files() const { return _liberty_files; } - - void set_timing_design_workspace(const std::string& workspace) { _timing_design_workspace = workspace; } - const std::string& get_timing_design_workspace() const { return _timing_design_workspace; } - - void set_power_net_name(const std::string& name) { _power_net_name = name; } - const std::string& get_power_net_name() const { return _power_net_name; } - - void set_egr_map_path(const std::string& egr_map_path) { _egr_map_path = egr_map_path; } - const std::string& get_egr_map_path() const { return _egr_map_path; } - - void set_pl_default_config_path(const std::string& pl_default_config_path) { _pl_default_config_path = pl_default_config_path; } - const std::string& get_pl_default_config_path() const { return _pl_default_config_path; } - - void set_sa_initial_temp(double initial_temp) { _sa_initial_temp = initial_temp; } - double get_sa_initial_temp() const { return _sa_initial_temp; } - - void set_sa_cooling_rate(double cooling_rate) { _sa_cooling_rate = cooling_rate; } - double get_sa_cooling_rate() const { return _sa_cooling_rate; } - - void set_sa_min_temp(double min_temp) { _sa_min_temp = min_temp; } - double get_sa_min_temp() const { return _sa_min_temp; } - - void set_sa_iterations_per_temp(int iterations) { _sa_iterations_per_temp = iterations; } - int get_sa_iterations_per_temp() const { return _sa_iterations_per_temp; } - - void set_sa_ir_drop_weight(double weight) { _sa_ir_drop_weight = weight; } - double get_sa_ir_drop_weight() const { return _sa_ir_drop_weight; } - - void set_sa_overflow_weight(double weight) { _sa_overflow_weight = weight; } - double get_sa_overflow_weight() const { return _sa_overflow_weight; } - - // Range of modifiable layers for simulated annealing algorithm - void set_sa_modifiable_layer_min(int layer) { _sa_modifiable_layer_min = layer; } - int get_sa_modifiable_layer_min() const { return _sa_modifiable_layer_min; } - - void set_sa_modifiable_layer_max(int layer) { _sa_modifiable_layer_max = layer; } - int get_sa_modifiable_layer_max() const { return _sa_modifiable_layer_max; } - - // Template configuration methods - void set_horizontal_templates(const std::vector& templates) { _horizontal_templates = templates; } - const std::vector& get_horizontal_templates() const { return _horizontal_templates; } - - void set_vertical_templates(const std::vector& templates) { _vertical_templates = templates; } - const std::vector& get_vertical_templates() const { return _vertical_templates; } - - private: - // design info - std::vector _lef_files; - std::string _def_path; - std::string _output_def_path; - std::string _sdc_file; - - // lib info - std::vector _liberty_files; - - // grid info - std::vector _power_layers; - int _ho_region_num; - int _ver_region_num; - - std::string _timing_design_workspace; - std::string _power_net_name; - std::string _egr_map_path; - std::string _pl_default_config_path; - - // sa info - double _sa_initial_temp; - double _sa_cooling_rate; - double _sa_min_temp; - int _sa_iterations_per_temp; - double _sa_ir_drop_weight; - double _sa_overflow_weight; - int _sa_modifiable_layer_min; - int _sa_modifiable_layer_max; + std::string _timing_design_workspace; + std::string _power_net_name; + std::string _egr_map_path; + std::string _pl_default_config_path; + std::string _report_path; - // template configuration - std::vector _horizontal_templates; - std::vector _vertical_templates; - }; + // sa info + double _sa_initial_temp; + double _sa_cooling_rate; + double _sa_min_temp; + int _sa_iterations_per_temp; + double _sa_ir_drop_weight; + double _sa_overflow_weight; + int _sa_modifiable_layer_min; + int _sa_modifiable_layer_max; - bool loadConfigFromJson(const std::string& config_file_path, PNPConfig* config); + // template configuration + std::vector _horizontal_templates; + std::vector _vertical_templates; + std::map _layer_specific_templates; +}; } // namespace ipnp diff --git a/src/operation/iPNP/source/data_manager/CMakeLists.txt b/src/operation/iPNP/source/data_manager/CMakeLists.txt index 8556f89c8f70595b072b71ae9ac32fe28a6151f8..fcf67dd97416390d2e19a1bb322a6c5f453a9d68 100644 --- a/src/operation/iPNP/source/data_manager/CMakeLists.txt +++ b/src/operation/iPNP/source/data_manager/CMakeLists.txt @@ -1,18 +1,20 @@ -add_library(data_manager - GridManager.cpp +add_library(pnp-data + PNPGridManager.cpp SingleTemplate.cpp TemplateLib.cpp - iPNPIdbWrapper.cpp + PNPIdbWrapper.cpp ) -target_link_libraries(data_manager +target_link_libraries(pnp-data PUBLIC idb - synthesis - + pnp-synthesis + pnp-config + log + idm ) -# target_include_directories( -# PUBLIC -# ${CMAKE_CURRENT_SOURCE_DIR} -# ) \ No newline at end of file +target_include_directories(pnp-data + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/src/operation/iPNP/source/data_manager/GridManager.cpp b/src/operation/iPNP/source/data_manager/PNPGridManager.cpp similarity index 79% rename from src/operation/iPNP/source/data_manager/GridManager.cpp rename to src/operation/iPNP/source/data_manager/PNPGridManager.cpp index 3eff7d72e7a7f5aa92875e9d6d5832eff12eae4f..95a4195b02361ba1e5ce4dce27690d8c3814c3d6 100644 --- a/src/operation/iPNP/source/data_manager/GridManager.cpp +++ b/src/operation/iPNP/source/data_manager/PNPGridManager.cpp @@ -15,14 +15,15 @@ // See the Mulan PSL v2 for more details. // *************************************************************************************** /** - * @file GridManager.cpp + * @file PNPGridManager.cpp * @author Jianrong Su * @brief * @version 1.0 * @date 2025-06-23 */ -#include "GridManager.hh" +#include "PNPGridManager.hh" + #include "PNPConfig.hh" namespace ipnp { @@ -31,32 +32,18 @@ PDNGridRegion::PDNGridRegion() : _shape(GridRegionShape::kRectangle) { } -PDNRectanGridRegion::PDNRectanGridRegion() -: _x_left_bottom(), -_y_left_bottom(), -_x_right_top(), -_y_right_top() +PDNRectanGridRegion::PDNRectanGridRegion() : _x_left_bottom(), _y_left_bottom(), _x_right_top(), _y_right_top() { } -void GridManager::init_GridManager_data() +void PNPGridManager::init_PNPGridManager_data() { - _template_libs.gen_template_libs(); - initialize_grid_data(_die_width, _die_height); -} + _template_libs.gen_template_libs_from_config(); -void GridManager::init_GridManager_data(const PNPConfig* config) -{ - if (config) { - _template_libs.gen_template_libs_from_config(config); - } else { - _template_libs.gen_template_libs(); - } - initialize_grid_data(_die_width, _die_height); } -void GridManager::initialize_grid_data(int32_t width, int32_t height) +void PNPGridManager::initialize_grid_data(int32_t width, int32_t height) { // Initialize 3D grid data _grid_data.resize(_layer_count); diff --git a/src/operation/iPNP/source/data_manager/GridManager.hh b/src/operation/iPNP/source/data_manager/PNPGridManager.hh similarity index 81% rename from src/operation/iPNP/source/data_manager/GridManager.hh rename to src/operation/iPNP/source/data_manager/PNPGridManager.hh index 2375fafb38807dd02d50820684a64e40b0730925..f9fa21c76d5a7a59d61a545a11dc100d15235866 100644 --- a/src/operation/iPNP/source/data_manager/GridManager.hh +++ b/src/operation/iPNP/source/data_manager/PNPGridManager.hh @@ -15,7 +15,7 @@ // See the Mulan PSL v2 for more details. // *************************************************************************************** /** - * @file GridManager.hh + * @file PNPGridManager.hh * @author Jianrong Su * @brief Grid manager for PDN * @version 1.0 @@ -26,15 +26,14 @@ #include #include -#include #include +#include + #include "SingleTemplate.hh" #include "TemplateLib.hh" namespace ipnp { -class PNPConfig; // Forward declaration - enum class GridRegionShape { kRectangle, @@ -104,11 +103,11 @@ class PDNRectanGridRegion : public PDNGridRegion /** * @brief Manager for PDN grid */ -class GridManager +class PNPGridManager { public: - GridManager() = default; - ~GridManager() = default; + PNPGridManager() = default; + ~PNPGridManager() = default; // Getters const std::vector& get_power_layers() const { return _power_layers; } @@ -128,7 +127,8 @@ class GridManager const TemplateLib& get_template_libs() const { return _template_libs; } // Setters - void set_power_layers(std::vector power_layers){ + void set_power_layers(std::vector power_layers) + { _power_layers = power_layers; _layer_count = power_layers.size(); } @@ -144,33 +144,33 @@ class GridManager void set_die_width(double die_width) { _die_width = die_width; } void set_die_height(double die_height) { _die_height = die_height; } void set_grid_data(std::vector>> grid_data) { _grid_data = grid_data; } - void set_single_template(int layer_idx, int row, int col, const SingleTemplate& single_template) { _template_data[layer_idx][row][col] = single_template; } + void set_single_template(int layer_idx, int row, int col, const SingleTemplate& single_template) + { + _template_data[layer_idx][row][col] = single_template; + } - // Initialize with default templates - void init_GridManager_data(); - // Initialize with templates from configuration - void init_GridManager_data(const PNPConfig* config); - -private: - std::vector _power_layers; // layers that have power nets - int _layer_count; // total number of layers - int _ho_region_num; // number of horizontal regions - int _ver_region_num; // number of vertical regions + void init_PNPGridManager_data(); + + private: + std::vector _power_layers; // layers that have power nets + int _layer_count; // total number of layers + int _ho_region_num; // number of horizontal regions + int _ver_region_num; // number of vertical regions int32_t _core_width; // width of the core int32_t _core_height; // height of the core - int32_t _die_width; // width of the core - int32_t _die_height; // height of the core - int32_t _core_llx; // left bottom x coordinate of the core - int32_t _core_lly; // left bottom y coordinate of the core - int32_t _core_urx; // right top x coordinate of the core - int32_t _core_ury; // right top y coordinate of the core - - std::vector> _power_nets; // only VDD VSS / VDD GND - std::vector>> _grid_data; // [layer][row][col] - std::vector>> _template_data; // [layer][row][col] - TemplateLib _template_libs; // Template library manager + int32_t _die_width; // width of the core + int32_t _die_height; // height of the core + int32_t _core_llx; // left bottom x coordinate of the core + int32_t _core_lly; // left bottom y coordinate of the core + int32_t _core_urx; // right top x coordinate of the core + int32_t _core_ury; // right top y coordinate of the core + + std::vector> _power_nets; // only VDD VSS / VDD GND + std::vector>> _grid_data; // [layer][row][col] + std::vector>> _template_data; // [layer][row][col] + TemplateLib _template_libs; // Template library manager void initialize_grid_data(int32_t width, int32_t height); }; diff --git a/src/operation/iPNP/source/data_manager/PNPIdbWrapper.cpp b/src/operation/iPNP/source/data_manager/PNPIdbWrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe7e6b0b0a3c56b4b5d7c5f76584952e4c4dad17 --- /dev/null +++ b/src/operation/iPNP/source/data_manager/PNPIdbWrapper.cpp @@ -0,0 +1,87 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file PNPIdbWrapper.cpp + * @author Jianrong Su + * @brief + * @version 1.0 + * @date 2025-06-23 + */ + +#include "PNPIdbWrapper.hh" + +#include +#include + +#include +#include +#include +#include + +#include "PowerRouter.hh" +#include "PowerVia.hh" +#include "idm.h" +#include "log/Log.hh" + +namespace ipnp { + +void PNPIdbWrapper::saveToIdb(PNPGridManager pnp_network) +{ + auto* idb_design = dmInst->get_idb_design(); + // clear VDD + auto* vdd_net = idb_design->get_special_net_list()->find_net("VDD"); + auto* vdd_wire_list = vdd_net->get_wire_list(); + vdd_wire_list->reset(); + + // clear VSS + auto* vss_net = idb_design->get_special_net_list()->find_net("VSS"); + auto* vss_wire_list = vss_net->get_wire_list(); + vss_wire_list->reset(); + + // add power/ground network to idb + PowerRouter* power_router = new PowerRouter(); + power_router->addPowerNets(pnp_network); + + // add via to idb + PowerVia* power_via = new PowerVia(); + power_via->connectAllPowerLayers(pnp_network); + + delete power_router; + delete power_via; + + LOG_INFO << "Added iPNP net."; +} + +void PNPIdbWrapper::writeIdbToDef(std::string def_file_path) +{ + bool success = dmInst->saveDef(def_file_path); + if (!success) { + LOG_INFO << "Successfully wrote DEF file to: " << def_file_path; + } else { + LOG_ERROR << "Error: Failed to save DEF file to: " << def_file_path; + } +} + +void PNPIdbWrapper::connect_M2_M1_Layer() +{ + PowerVia* power_via = new PowerVia(); + power_via->connectM2M1Layer(); + + delete power_via; +} + +} // namespace ipnp diff --git a/src/operation/iPNP/api/iPNPApi.hh b/src/operation/iPNP/source/data_manager/PNPIdbWrapper.hh similarity index 76% rename from src/operation/iPNP/api/iPNPApi.hh rename to src/operation/iPNP/source/data_manager/PNPIdbWrapper.hh index 0383ee2ac01773d66133b657e3127a7deb3afc05..f3a44404804b3f7a160417d9b1248890d8a84c7d 100644 --- a/src/operation/iPNP/api/iPNPApi.hh +++ b/src/operation/iPNP/source/data_manager/PNPIdbWrapper.hh @@ -15,36 +15,36 @@ // See the Mulan PSL v2 for more details. // *************************************************************************************** /** - * @file iPNPApi.hh + * @file PNPIdbWrapper.hh * @author Jianrong Su * @brief * @version 1.0 * @date 2025-06-23 */ -#ifndef IPNP_API_HH -#define IPNP_API_HH - #pragma once + #include +#include #include -#include +#include -#include "log/Log.hh" +#include "PNPGridManager.hh" namespace ipnp { -class iPNP; +class PNPIdbWrapper +{ + public: + PNPIdbWrapper() = default; + ~PNPIdbWrapper() = default; -class iPNPApi { -public: - static void setInstance(iPNP* ipnp); - static iPNP* getInstance(); + void saveToIdb(PNPGridManager pnp_network); + void writeIdbToDef(std::string def_file_path); -private: - static iPNP* _ipnp_instance; + void connect_M2_M1_Layer(); + + private: }; } // namespace ipnp - -#endif // IPNP_API_HH \ No newline at end of file diff --git a/src/operation/iPNP/source/data_manager/TemplateLib.cpp b/src/operation/iPNP/source/data_manager/TemplateLib.cpp index edc031eb5571918a77e34a378cb486c7e71fd895..b63762e3357d58c307843da69b50deb9a868cd3b 100644 --- a/src/operation/iPNP/source/data_manager/TemplateLib.cpp +++ b/src/operation/iPNP/source/data_manager/TemplateLib.cpp @@ -23,15 +23,12 @@ */ #include "TemplateLib.hh" + #include "log/Log.hh" namespace ipnp { -SingleTemplate TemplateLib::gen_single_template(StripeDirection direction, - double width, - double pg_offset, - double space, - double offset) +SingleTemplate TemplateLib::gen_single_template(StripeDirection direction, double width, double pg_offset, double space, double offset) { SingleTemplate single_template(direction, PowerType::kVSS, width, pg_offset, space, offset); return single_template; @@ -50,21 +47,15 @@ void TemplateLib::gen_template_libs() _vertical_templates.push_back(gen_single_template(StripeDirection::kVertical, 8000.0, 1600.0, 38400.0, 27200.0)); } -void TemplateLib::gen_template_libs_from_config(const PNPConfig* config) +void TemplateLib::gen_template_libs_from_config() { - if (!config) { - LOG_WARNING << "PNPConfig is null, using default hardcoded templates." << std::endl; - gen_template_libs(); - return; - } - // Clear existing templates _horizontal_templates.clear(); _vertical_templates.clear(); // Get templates from config - const auto& horizontal_templates = config->get_horizontal_templates(); - const auto& vertical_templates = config->get_vertical_templates(); + const auto& horizontal_templates = pnpConfig->get_horizontal_templates(); + const auto& vertical_templates = pnpConfig->get_vertical_templates(); // Check if both template vectors are empty if (horizontal_templates.empty() && vertical_templates.empty()) { @@ -75,32 +66,18 @@ void TemplateLib::gen_template_libs_from_config(const PNPConfig* config) // Process horizontal templates for (const auto& template_config : horizontal_templates) { - _horizontal_templates.push_back( - gen_single_template( - StripeDirection::kHorizontal, - template_config.width, - template_config.pg_offset, - template_config.space, - template_config.offset - ) - ); + _horizontal_templates.push_back(gen_single_template(StripeDirection::kHorizontal, template_config.width, template_config.pg_offset, + template_config.space, template_config.offset)); } // Process vertical templates for (const auto& template_config : vertical_templates) { - _vertical_templates.push_back( - gen_single_template( - StripeDirection::kVertical, - template_config.width, - template_config.pg_offset, - template_config.space, - template_config.offset - ) - ); + _vertical_templates.push_back(gen_single_template(StripeDirection::kVertical, template_config.width, template_config.pg_offset, + template_config.space, template_config.offset)); } - LOG_INFO << "Generated " << _horizontal_templates.size() << " horizontal templates and " - << _vertical_templates.size() << " vertical templates from configuration." << std::endl; + LOG_INFO << "Generated " << _horizontal_templates.size() << " horizontal templates and " << _vertical_templates.size() + << " vertical templates from configuration." << std::endl; } -} // namespace ipnp \ No newline at end of file +} // namespace ipnp \ No newline at end of file diff --git a/src/operation/iPNP/source/data_manager/TemplateLib.hh b/src/operation/iPNP/source/data_manager/TemplateLib.hh index 949c2e825444b1a295179266f5ff046c260c4002..34a11e0c59367ed3338c83a55b2ff9e30cd5740c 100644 --- a/src/operation/iPNP/source/data_manager/TemplateLib.hh +++ b/src/operation/iPNP/source/data_manager/TemplateLib.hh @@ -25,8 +25,9 @@ #pragma once #include -#include "SingleTemplate.hh" + #include "PNPConfig.hh" +#include "SingleTemplate.hh" namespace ipnp { @@ -39,19 +40,15 @@ class TemplateLib TemplateLib() = default; ~TemplateLib() = default; - SingleTemplate gen_single_template(StripeDirection direction, - double width, - double pg_offset, - double space, - double offset); + SingleTemplate gen_single_template(StripeDirection direction, double width, double pg_offset, double space, double offset); // Generate template libraries using hardcoded values (legacy method) void gen_template_libs(); - + // Generate template libraries from configuration - void gen_template_libs_from_config(const PNPConfig* config); + void gen_template_libs_from_config(); - const std::vector& get_horizontal_templates() const { return _horizontal_templates; } + const std::vector& get_horizontal_templates() const { return _horizontal_templates; } const std::vector& get_vertical_templates() const { return _vertical_templates; } private: diff --git a/src/operation/iPNP/source/data_manager/iPNPIdbWrapper.cpp b/src/operation/iPNP/source/data_manager/iPNPIdbWrapper.cpp deleted file mode 100644 index 61b287288b2460f271e838e40d113139b5dd0d05..0000000000000000000000000000000000000000 --- a/src/operation/iPNP/source/data_manager/iPNPIdbWrapper.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// *************************************************************************************** -// Copyright (c) 2023-2025 Peng Cheng Laboratory -// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences -// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip -// -// iEDA is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// -// See the Mulan PSL v2 for more details. -// *************************************************************************************** -/** - * @file iPNPIdbWrapper.cpp - * @author Jianrong Su - * @brief - * @version 1.0 - * @date 2025-06-23 - */ - -#include "iPNPIdbWrapper.hh" - -#include -#include -#include -#include -#include -#include - -#include "PowerVia.hh" -#include "PowerRouter.hh" - -namespace ipnp { - - void iPNPIdbWrapper::saveToIdb(GridManager pnp_network) - { - // clear VDD - auto* vdd_net = _idb_design->get_special_net_list()->find_net("VDD"); - auto* vdd_wire_list = vdd_net->get_wire_list(); - vdd_wire_list->reset(); - - // clear VSS - auto* vss_net = _idb_design->get_special_net_list()->find_net("VSS"); - auto* vss_wire_list = vss_net->get_wire_list(); - vss_wire_list->reset(); - - // add power/ground network to idb - PowerRouter* power_router = new PowerRouter(); - power_router->addPowerNets(_idb_design, pnp_network); - - // add via to idb - PowerVia* power_via = new PowerVia(); - _idb_design = power_via->connectAllPowerLayers(pnp_network, _idb_design); - - delete power_router; - delete power_via; - - std::cout << "[iPNP info]: Added iPNP net." << std::endl; - } - - void iPNPIdbWrapper::writeIdbToDef(std::string def_file_path) - { - if (!_idb_design) { - std::cerr << "Error: IDB design is null in writeIdbToDef" << std::endl; - return; - } - - auto* db_builder = get_idb_builder(); - if (!db_builder) { - std::cerr << "Error: Failed to create IdbBuilder" << std::endl; - return; - } - - auto* def_service = db_builder->get_def_service(); - if (!def_service) { - std::cerr << "Error: DEF service is null" << std::endl; - delete db_builder; - return; - } - - auto* layout = _idb_design->get_layout(); - if (!layout) { - std::cerr << "Error: Layout is null" << std::endl; - delete db_builder; - return; - } - - def_service->set_layout(layout); - - bool success = db_builder->saveDef(def_file_path); - if (!success) { - std::cout << "Successfully wrote DEF file to: " << def_file_path << std::endl; - } - else { - std::cerr << "Error: Failed to save DEF file to: " << def_file_path << std::endl; - } - } - - void iPNPIdbWrapper::connect_M2_M1_Layer() - { - PowerVia* power_via = new PowerVia(); - _idb_design = power_via->connectM2M1Layer(_idb_design); - - delete power_via; - } - -} // namespace ipnp diff --git a/src/operation/iPNP/source/data_manager/iPNPIdbWrapper.hh b/src/operation/iPNP/source/data_manager/iPNPIdbWrapper.hh deleted file mode 100644 index 801c43d6b13ca44e9790eed81052b65805fd4ece..0000000000000000000000000000000000000000 --- a/src/operation/iPNP/source/data_manager/iPNPIdbWrapper.hh +++ /dev/null @@ -1,99 +0,0 @@ -// *************************************************************************************** -// Copyright (c) 2023-2025 Peng Cheng Laboratory -// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences -// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip -// -// iEDA is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// -// See the Mulan PSL v2 for more details. -// *************************************************************************************** -/** - * @file iPNPIdbWrapper.hh - * @author Jianrong Su - * @brief - * @version 1.0 - * @date 2025-06-23 - */ - -#pragma once - -#include -#include -#include -#include - -#include "GridManager.hh" -#include "PowerRouter.hh" - -namespace idb { -class IdbDesign; -class IdbSpecialNet; -class IdbSpecialNetList; -class IdbSpecialWireList; -class IdbSpecialWire; -class IdbSpecialWireSegment; -class IdbLayer; -class IdbVia; -class IdbPin; -class IdbRect; -class IdbInstance; - -enum class SegmentType : int8_t; -enum class IdbWireShapeType : uint8_t; -enum class IdbOrient : uint8_t; - -template -class IdbCoordinate; -} // namespace idb - -namespace ipnp { - -class iPNPIdbWrapper -{ - public: - iPNPIdbWrapper(idb::IdbDesign* idb_design) : _idb_design(idb_design) {} - iPNPIdbWrapper() = default; - ~iPNPIdbWrapper() = default; - - // get die infomation from iDB - int32_t get_input_die_llx() { return _idb_design->get_layout()->get_die()->get_llx(); } // The smallest x-coordinate of the die rectangle - int32_t get_input_die_lly() { return _idb_design->get_layout()->get_die()->get_lly(); } // The smallest y-coordinate of the die rectangle - int32_t get_input_die_urx() { return _idb_design->get_layout()->get_die()->get_urx(); } // The largest x-coordinate of the die rectangle - int32_t get_input_die_ury() { return _idb_design->get_layout()->get_die()->get_ury(); } // The largest y-coordinate of the die rectangle - int32_t get_input_die_width() { return _idb_design->get_layout()->get_die()->get_width(); } - int32_t get_input_die_height() { return _idb_design->get_layout()->get_die()->get_height(); } - uint64_t get_input_die_area() { return _idb_design->get_layout()->get_die()->get_area(); } - - // get core infomation from iDB - int32_t get_input_core_lx() { return _idb_design->get_layout()->get_core()->get_bounding_box()->get_low_x(); } - int32_t get_input_core_ly() { return _idb_design->get_layout()->get_core()->get_bounding_box()->get_low_y(); } - int32_t get_input_core_hx() { return _idb_design->get_layout()->get_core()->get_bounding_box()->get_high_x(); } - int32_t get_input_core_hy() { return _idb_design->get_layout()->get_core()->get_bounding_box()->get_high_y(); } - int32_t get_input_core_width() { return _idb_design->get_layout()->get_core()->get_bounding_box()->get_width(); } - int32_t get_input_core_height() { return _idb_design->get_layout()->get_core()->get_bounding_box()->get_height(); } - uint64_t get_input_core_area() { return _idb_design->get_layout()->get_core()->get_bounding_box()->get_area(); } - - auto* get_idb_design() { return _idb_design; } - void set_idb_design(idb::IdbDesign* idb_design) { _idb_design = idb_design; } - - auto* get_idb_builder() { return _idb_builder; } - void set_idb_builder(idb::IdbBuilder* idb_builder) { _idb_builder = idb_builder; } - - void saveToIdb(GridManager pnp_network); - void writeIdbToDef(std::string def_file_path); - - void connect_M2_M1_Layer(); - - private: - idb::IdbDesign* _idb_design = nullptr; - idb::IdbBuilder* _idb_builder = nullptr; -}; - -} // namespace ipnp diff --git a/src/operation/iPNP/source/iPNP.cpp b/src/operation/iPNP/source/iPNP.cpp deleted file mode 100644 index a6429a3c667a220de18e9cce91346b8d7f96449f..0000000000000000000000000000000000000000 --- a/src/operation/iPNP/source/iPNP.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// *************************************************************************************** -// Copyright (c) 2023-2025 Peng Cheng Laboratory -// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences -// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip -// -// iEDA is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// -// See the Mulan PSL v2 for more details. -// *************************************************************************************** -/** - * @file iPNP.cpp - * @author Jianrong Su - * @brief - * @version 1.0 - * @date 2025-06-23 - */ - -#include "iPNP.hh" - -#include "FastPlacer.hh" -#include "NetworkSynthesis.hh" -#include "PdnOptimizer.hh" -#include "iPNPIdbWrapper.hh" -#include "CongestionEval.hh" -#include "IREval.hh" -#include "PNPConfig.hh" -#include "log/Log.hh" - -namespace ipnp { - - iPNP::iPNP() { - _pnp_config = new PNPConfig(); - } - - iPNP::iPNP(const std::string& config_file) { - _pnp_config = new PNPConfig(); - if (!loadConfigFromJson(config_file, _pnp_config)) { - LOG_WARNING << "Initializing iPNP with default configuration" << std::endl; - } - - // If LEF and DEF file paths are specified in the configuration, read the DEF file - if (!_pnp_config->get_lef_files().empty() && !_pnp_config->get_def_path().empty()) { - readLefDef(_pnp_config->get_lef_files(), _pnp_config->get_def_path()); - LOG_INFO << "DEF file read: " << _pnp_config->get_def_path() << std::endl; - } - else { - LOG_WARNING << "LEF files or DEF file path not specified in configuration" << std::endl; - } - - // Set output DEF file path - if (!_pnp_config->get_output_def_path().empty()) { - _output_def_path = _pnp_config->get_output_def_path(); - } - else { - _output_def_path = "./output.def"; - } - } - - iPNP::~iPNP() { - if (_pnp_config) { - delete _pnp_config; - _pnp_config = nullptr; - } - } - - void iPNP::runSynthesis() - { - NetworkSynthesis network_synthesizer(SysnType::kDefault, _input_network); - network_synthesizer.synthesizeNetwork(); - _initialized_network = network_synthesizer.get_network(); - _current_opt_network = _initialized_network; - } - - void iPNP::runOptimize() - { - saveToIdb(); - - PdnOptimizer pdn_optimizer; - pdn_optimizer.optimizeGlobal(_initialized_network, _idb_wrapper.get_idb_builder()); - _current_opt_network = pdn_optimizer.get_out_put_grid(); - } - - void iPNP::runFastPlacer() - { - FastPlacer fast_placer; - fast_placer.runFastPlacer(_idb_wrapper.get_idb_builder()); - } - - void iPNP::readLefDef(std::vector lef_files, std::string def_path) - { - auto* db_builder = new idb::IdbBuilder(); - db_builder->buildLef(lef_files); - db_builder->buildDef(def_path); - - auto* idb_design = db_builder->get_def_service()->get_design(); - - _idb_wrapper.set_idb_design(idb_design); - _idb_wrapper.set_idb_builder(db_builder); - } - - void iPNP::init() - { - // Initialize the input network - _input_network = GridManager(); - if (_pnp_config) { - _input_network.set_power_layers(_pnp_config->get_power_layers()); - _input_network.set_ho_region_num(_pnp_config->get_ho_region_num()); - _input_network.set_ver_region_num(_pnp_config->get_ver_region_num()); - } - else { - _input_network.set_power_layers({ 9,8,7,6,5,4,3 }); - _input_network.set_ho_region_num(2); - _input_network.set_ver_region_num(2); - } - _input_network.set_layer_count(_input_network.get_power_layers().size()); - _input_network.set_die_width(_idb_wrapper.get_input_die_width()); - _input_network.set_die_height(_idb_wrapper.get_input_die_height()); - - // Initialize with configuration-based templates if available - if (_pnp_config) { - _input_network.init_GridManager_data(_pnp_config); - } - else { - _input_network.init_GridManager_data(); - } - - } - - void iPNP::initIRAnalysis() { - // Initialize IREval - _ir_eval.initIREval(_idb_wrapper.get_idb_builder(), _pnp_config); - - } - - void iPNP::runAnalysis() - { - saveToIdb(); - - _cong_eval.set_config(_pnp_config); - _cong_eval.evalEGR(_idb_wrapper.get_idb_builder()); - - initIRAnalysis(); - _ir_eval.runIREval(_idb_wrapper.get_idb_builder()); - } - - void iPNP::outputDef() - { - readLefDef(_pnp_config->get_lef_files(), _pnp_config->get_def_path()); - saveToIdb(); - writeIdbToDef(_output_def_path); - } - - void iPNP::connect_M2_M1() - { - _idb_wrapper.connect_M2_M1_Layer(); - } - - void iPNP::run() - { - if (_idb_wrapper.get_idb_design()) { - - init(); - runSynthesis(); - runFastPlacer(); - runOptimize(); - runAnalysis(); - outputDef(); - - - LOG_INFO << "Output written to DEF file: " << _output_def_path << std::endl; - - } - else { - LOG_ERROR << "Warning: idb design is empty!" << std::endl; - } - } - -} // namespace ipnp diff --git a/src/operation/iPNP/source/iPNP.hh b/src/operation/iPNP/source/iPNP.hh deleted file mode 100644 index ede95ef4de2fd854d7b233a67d521409a86413fd..0000000000000000000000000000000000000000 --- a/src/operation/iPNP/source/iPNP.hh +++ /dev/null @@ -1,111 +0,0 @@ -// *************************************************************************************** -// Copyright (c) 2023-2025 Peng Cheng Laboratory -// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences -// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip -// -// iEDA is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// -// See the Mulan PSL v2 for more details. -// *************************************************************************************** -/** - * @file iPNP.hh - * @author Xinhao li - * @brief Top level file of iPNP module. - * @version 0.1 - * @date 2024-07-15 - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "GridManager.hh" -#include "iPNPIdbWrapper.hh" -#include "CongestionEval.hh" -#include "IREval.hh" - -namespace idb { - class IdbLayer; - class IdbSpecialWireSegment; - class IdbRegularWireSegment; - class IdbBlockageList; - class IdbInstance; - class IdbRect; - class IdbVia; - class IdbLayerCut; - class IdbPin; - class IdbSpecialNet; - class IdbLayerRouting; - class IdbSpecialWire; - class IdbDesign; - - enum class SegmentType : int8_t; - enum class IdbWireShapeType : uint8_t; - enum class IdbOrient : uint8_t; - - template - class IdbCoordinate; -} // namespace idb - -namespace ipnp { - - class PNPConfig; - - class iPNP - { - public: - iPNP(); - iPNP(const std::string& config_file); - ~iPNP(); - - PNPConfig* get_config() { return _pnp_config; } - GridManager get_initialized_network() { return _initialized_network; } - GridManager get_current_opt_network() { return _current_opt_network; } - - void readLefDef(std::vector lef_files, std::string def_path); - void setIdb(idb::IdbDesign* input_idb_design) { _idb_wrapper.set_idb_design(input_idb_design); } - - void init(); - void initIRAnalysis(); - void runSynthesis(); - void runOptimize(); // including calling Evaluator and modify PDN - void runFastPlacer(); - void saveToIdb() { _idb_wrapper.saveToIdb(_current_opt_network); } - void writeIdbToDef(std::string def_path) { _idb_wrapper.writeIdbToDef(def_path); } - void runAnalysis(); - void outputDef(); - - void connect_M2_M1(); - - void run(); // According to the config. e.g. which Evaluator, which opt algorithm. - - // Set the output DEF file path - void set_output_def_path(const std::string& path) { _output_def_path = path; } - - private: - PNPConfig* _pnp_config = nullptr; - GridManager _input_network; - GridManager _initialized_network; - GridManager _current_opt_network; - idb::IdbInstanceList* _input_instance_list; - - iPNPIdbWrapper _idb_wrapper; - IREval _ir_eval; - CongestionEval _cong_eval; - - std::string _output_def_path; - }; - -} // namespace ipnp diff --git a/src/operation/iPNP/source/module/CMakeLists.txt b/src/operation/iPNP/source/module/CMakeLists.txt index da3be8e29e9ef8baf75d7fd6e00cd0fd752f09f6..027229da277efe46ffaac986df36358c3d784cd2 100644 --- a/src/operation/iPNP/source/module/CMakeLists.txt +++ b/src/operation/iPNP/source/module/CMakeLists.txt @@ -1,4 +1,7 @@ add_subdirectory(evaluator) add_subdirectory(optimizer) add_subdirectory(synthesis) -add_subdirectory(tcl-cmd) + +if(BUILD_PNP_EXECUTE) + add_subdirectory(pnp-cmd) +endif() diff --git a/src/operation/iPNP/source/module/evaluator/CMakeLists.txt b/src/operation/iPNP/source/module/evaluator/CMakeLists.txt index cf3c125cac5a61385e181c7367acd11b7dbb410c..e04630135c93e630c3494b0e9935d3ea2773c2ae 100644 --- a/src/operation/iPNP/source/module/evaluator/CMakeLists.txt +++ b/src/operation/iPNP/source/module/evaluator/CMakeLists.txt @@ -1,4 +1,13 @@ -add_library(evaluator CongestionEval.cpp IREval.cpp FastPlacer.cpp DRCEval.cpp) +add_library(pnp-evaluator +CongestionEval.cpp +IREval.cpp +FastPlacer.cpp +DRCEval.cpp +) -target_link_libraries(evaluator PUBLIC power ista-engine eval_density_api eval_congestion_api eval_db ipl-api - data_manager) +target_link_libraries(pnp-evaluator PUBLIC power ista-engine pnp-data ipl-api pnp-config) + +target_include_directories(pnp-evaluator + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/src/operation/iPNP/source/module/evaluator/CongestionEval.cpp b/src/operation/iPNP/source/module/evaluator/CongestionEval.cpp index 47853c2376b3200b631aa9b09d38764efbb9548e..ac232726bcac4696cf9a616939734ef8eea865d8 100644 --- a/src/operation/iPNP/source/module/evaluator/CongestionEval.cpp +++ b/src/operation/iPNP/source/module/evaluator/CongestionEval.cpp @@ -23,33 +23,29 @@ */ #include "CongestionEval.hh" -#include "idm.h" -#include "congestion_api.h" + #include "PNPConfig.hh" +#include "congestion_api.h" +#include "idm.h" namespace ipnp { - void CongestionEval::evalEGR(idb::IdbBuilder* idb_builder) - { - dmInst->set_idb_builder(idb_builder); - dmInst->set_idb_def_service(idb_builder->get_def_service()); - dmInst->set_idb_lef_service(idb_builder->get_lef_service()); +void CongestionEval::evalEGR() +{ + std::string map_path; + std::string stage = "place"; - std::string map_path; - std::string stage = "place"; - - if (_config != nullptr && !_config->get_egr_map_path().empty()) { - map_path = _config->get_egr_map_path(); - } else { - map_path = "../src/operation/iPNP/example"; - } - - ieval::CongestionAPI congestion_api; - ieval::OverflowSummary overflow_summary; + if (!pnpConfig->get_egr_map_path().empty()) { + map_path = pnpConfig->get_egr_map_path(); + } else { + map_path = "../src/operation/iPNP/example"; + } - std::string temp = congestion_api.egrUnionMap(stage, map_path); - overflow_summary = congestion_api.egrOverflow(stage, temp); - _total_overflow_union = overflow_summary.total_overflow_union; + ieval::CongestionAPI congestion_api; + ieval::OverflowSummary overflow_summary; - } + std::string temp = congestion_api.egrUnionMap(stage, map_path); + overflow_summary = congestion_api.egrOverflow(stage, temp); + _total_overflow_union = overflow_summary.total_overflow_union; +} } // namespace ipnp \ No newline at end of file diff --git a/src/operation/iPNP/source/module/evaluator/CongestionEval.hh b/src/operation/iPNP/source/module/evaluator/CongestionEval.hh index e76bcbcc591a1488bd40debf021ab30df5f2918e..ce78a0220e779c82f3f2815bec14a18c7aa04d96 100644 --- a/src/operation/iPNP/source/module/evaluator/CongestionEval.hh +++ b/src/operation/iPNP/source/module/evaluator/CongestionEval.hh @@ -29,26 +29,19 @@ #include #include -#include "iPNPCommon.hh" - namespace ipnp { -class PNPConfig; - class CongestionEval { public: - CongestionEval() : _config(nullptr), _total_overflow_union(0) {} + CongestionEval() = default; ~CongestionEval() = default; - void evalEGR(idb::IdbBuilder* idb_builder); + void evalEGR(); int32_t get_total_overflow_union() { return _total_overflow_union; } - - void set_config(PNPConfig* config) { _config = config; } - -private: - PNPConfig* _config; - int32_t _total_overflow_union; + + private: + int32_t _total_overflow_union = 0; }; } // namespace ipnp diff --git a/src/operation/iPNP/source/module/evaluator/FastPlacer.cpp b/src/operation/iPNP/source/module/evaluator/FastPlacer.cpp index 807e327f348f5f2911cfadd57513bf7b5b2af773..557835d03777cd0066f72789d3daeaf37811432d 100644 --- a/src/operation/iPNP/source/module/evaluator/FastPlacer.cpp +++ b/src/operation/iPNP/source/module/evaluator/FastPlacer.cpp @@ -23,28 +23,27 @@ */ #include "FastPlacer.hh" + #include "PLAPI.hh" -#include "log/Log.hh" #include "PNPConfig.hh" +#include "idm.h" +#include "log/Log.hh" namespace ipnp { -void FastPlacer::runFastPlacer(idb::IdbBuilder* idb_builder) +void FastPlacer::runFastPlacer() { std::string pl_json_file; - - PNPConfig* temp_config = new PNPConfig(); - if (!temp_config->get_pl_default_config_path().empty()) { - pl_json_file = temp_config->get_pl_default_config_path(); - } - else { + + if (!pnpConfig->get_pl_default_config_path().empty()) { + pl_json_file = pnpConfig->get_pl_default_config_path(); + } else { pl_json_file = "../src/operation/iPNP/example/pl_default_config.json"; } - delete temp_config; - + ipl::PLAPI& plapi = ipl::PLAPI::getInst(); - plapi.initAPI(pl_json_file, idb_builder); + plapi.initAPI(pl_json_file, dmInst->get_idb_builder()); plapi.runGP(); plapi.runLG(); plapi.writeBackSourceDataBase(); @@ -53,5 +52,4 @@ void FastPlacer::runFastPlacer(idb::IdbBuilder* idb_builder) plapi.destoryInst(); } - } // namespace ipnp diff --git a/src/operation/iPNP/source/module/evaluator/FastPlacer.hh b/src/operation/iPNP/source/module/evaluator/FastPlacer.hh index c0f5b7452cfe6fa7d2b0f0e2a0d8c8bd1a6bc772..f11c99909581f2a3cebaddde21dc70856e2d95f0 100644 --- a/src/operation/iPNP/source/module/evaluator/FastPlacer.hh +++ b/src/operation/iPNP/source/module/evaluator/FastPlacer.hh @@ -27,27 +27,26 @@ #include namespace idb { - class IdbDesign; - class IdbBuilder; -} +class IdbDesign; +class IdbBuilder; +} // namespace idb namespace ipl { - class PLAPI; - extern PLAPI& iPLAPIInst; -} +class PLAPI; +extern PLAPI& iPLAPIInst; +} // namespace ipl namespace ipnp { + class FastPlacer { public: FastPlacer() = default; ~FastPlacer() = default; - void runFastPlacer(idb::IdbBuilder* idb_builder); - + void runFastPlacer(); -private: - + private: }; } // namespace ipnp diff --git a/src/operation/iPNP/source/module/evaluator/IREval.cpp b/src/operation/iPNP/source/module/evaluator/IREval.cpp index b4d7e3a3109bf56eaf0a23c7dce444e2712d707c..562cefd47c2d87df20fc576a3164bab1fb6dfaa4 100644 --- a/src/operation/iPNP/source/module/evaluator/IREval.cpp +++ b/src/operation/iPNP/source/module/evaluator/IREval.cpp @@ -23,116 +23,117 @@ */ #include "IREval.hh" -#include "iPNPIdbWrapper.hh" + +#include "PNPIdbWrapper.hh" +#include "idm.h" #include "log/Log.hh" namespace ipnp { - void IREval::runIREval(idb::IdbBuilder* idb_builder) - { - _power_engine = ipower::PowerEngine::getOrCreatePowerEngine(); +void IREval::runIREval() +{ + _power_engine = ipower::PowerEngine::getOrCreatePowerEngine(); - std::string power_net_name = "VDD"; + std::string power_net_name = "VDD"; - _power_engine->resetIRAnalysisData(); - _power_engine->buildPGNetWireTopo(); - _power_engine->runIRAnalysis(power_net_name); + _power_engine->resetIRAnalysisData(); + _power_engine->buildPGNetWireTopo(); + _power_engine->runIRAnalysis(power_net_name); - _power_engine->reportIRAnalysis(); + _power_engine->reportIRAnalysis(); - _coord_ir_map = _power_engine->displayIRDropMap(); - } + _coord_ir_map = _power_engine->displayIRDropMap(); +} - void IREval::initIREval(idb::IdbBuilder* idb_builder, PNPConfig* pnp_config) - { - LOG_INFO << "Start initialize IREval"; +void IREval::initIREval() +{ + LOG_INFO << "Start initialize IREval"; - _timing_engine = TimingEngine::getOrCreateTimingEngine(); - _timing_engine->set_num_threads(48); + _timing_engine = TimingEngine::getOrCreateTimingEngine(); + _timing_engine->set_num_threads(48); - // Set working directory - std::string design_work_space = "./"; - if (pnp_config && !pnp_config->get_timing_design_workspace().empty()) { - design_work_space = pnp_config->get_timing_design_workspace(); - } - _timing_engine->set_design_work_space(design_work_space.c_str()); - - std::vector lib_files; - if (pnp_config && !pnp_config->get_liberty_files().empty()) { - const auto& liberty_files = pnp_config->get_liberty_files(); - lib_files.reserve(liberty_files.size()); - for (const auto& lib : liberty_files) { - lib_files.push_back(lib.c_str()); - } + // Set working directory + std::string design_work_space = "./"; + if (!pnpConfig->get_timing_design_workspace().empty()) { + design_work_space = pnpConfig->get_timing_design_workspace(); + } + _timing_engine->set_design_work_space(design_work_space.c_str()); + + std::vector lib_files; + if (!pnpConfig->get_liberty_files().empty()) { + const auto& liberty_files = pnpConfig->get_liberty_files(); + lib_files.reserve(liberty_files.size()); + for (const auto& lib : liberty_files) { + lib_files.push_back(lib.c_str()); } - _timing_engine->readLiberty(lib_files); + } + _timing_engine->readLiberty(lib_files); - _timing_engine->get_ista()->set_analysis_mode(ista::AnalysisMode::kMaxMin); - _timing_engine->get_ista()->set_n_worst_path_per_clock(1); + _timing_engine->get_ista()->set_analysis_mode(ista::AnalysisMode::kMaxMin); + _timing_engine->get_ista()->set_n_worst_path_per_clock(1); - // Read DEF design - _timing_engine->setDefDesignBuilder(idb_builder); + // Read DEF design + _timing_engine->setDefDesignBuilder(dmInst->get_idb_builder()); - // Read SDC file - std::string sdc_file; - if (pnp_config && !pnp_config->get_sdc_file().empty()) { - sdc_file = pnp_config->get_sdc_file(); - _timing_engine->readSdc(sdc_file.c_str()); - } + // Read SDC file + std::string sdc_file; + if (!pnpConfig->get_sdc_file().empty()) { + sdc_file = pnpConfig->get_sdc_file(); + _timing_engine->readSdc(sdc_file.c_str()); + } - _timing_engine->buildGraph(); - _timing_engine->get_ista()->updateTiming(); - _timing_engine->reportTiming(); + _timing_engine->buildGraph(); + _timing_engine->get_ista()->updateTiming(); + _timing_engine->reportTiming(); - _ista = Sta::getOrCreateSta(); - _ipower = ipower::Power::getOrCreatePower(&(_ista->get_graph())); + _ista = Sta::getOrCreateSta(); + _ipower = ipower::Power::getOrCreatePower(&(_ista->get_graph())); - _ipower->runCompleteFlow(); + _ipower->runCompleteFlow(); - LOG_INFO << "End initialize IREval"; + LOG_INFO << "End initialize IREval"; +} +double IREval::getMaxIRDrop() const +{ + if (_coord_ir_map.empty()) { + return 0.0; } - - double IREval::getMaxIRDrop() const - { - if (_coord_ir_map.empty()) { - return 0.0; - } - double max_ir_drop = -std::numeric_limits::max(); - for (auto it = _coord_ir_map.begin(); it != _coord_ir_map.end(); ++it) { - if (it->second > max_ir_drop) { - max_ir_drop = it->second; - } + double max_ir_drop = -std::numeric_limits::max(); + for (auto it = _coord_ir_map.begin(); it != _coord_ir_map.end(); ++it) { + if (it->second > max_ir_drop) { + max_ir_drop = it->second; } - return max_ir_drop; } + return max_ir_drop; +} - double IREval::getMinIRDrop() const - { - if (_coord_ir_map.empty()) { - return 0.0; - } - double min_ir_drop = std::numeric_limits::max(); - for (auto it = _coord_ir_map.begin(); it != _coord_ir_map.end(); ++it) { - if (it->second < min_ir_drop) { - min_ir_drop = it->second; - } +double IREval::getMinIRDrop() const +{ + if (_coord_ir_map.empty()) { + return 0.0; + } + double min_ir_drop = std::numeric_limits::max(); + for (auto it = _coord_ir_map.begin(); it != _coord_ir_map.end(); ++it) { + if (it->second < min_ir_drop) { + min_ir_drop = it->second; } - return min_ir_drop; } + return min_ir_drop; +} - double IREval::getAvgIRDrop() const - { - if (_coord_ir_map.empty()) { - return 0.0; - } - double sum_ir_drop = 0.0; - int count = 0; - for (auto it = _coord_ir_map.begin(); it != _coord_ir_map.end(); ++it) { - sum_ir_drop += it->second; - count++; - } - return sum_ir_drop / count; +double IREval::getAvgIRDrop() const +{ + if (_coord_ir_map.empty()) { + return 0.0; + } + double sum_ir_drop = 0.0; + int count = 0; + for (auto it = _coord_ir_map.begin(); it != _coord_ir_map.end(); ++it) { + sum_ir_drop += it->second; + count++; } + return sum_ir_drop / count; +} } // namespace ipnp \ No newline at end of file diff --git a/src/operation/iPNP/source/module/evaluator/IREval.hh b/src/operation/iPNP/source/module/evaluator/IREval.hh index bf457e35330a43a28b6b731e3ec23658cb700b94..d89a5a4c0bfb0a988b07476ea16c7c0a90b69229 100644 --- a/src/operation/iPNP/source/module/evaluator/IREval.hh +++ b/src/operation/iPNP/source/module/evaluator/IREval.hh @@ -37,11 +37,6 @@ #include "api/Power.hh" #include "PNPConfig.hh" -namespace idb { - class IdbDesign; - class IdbBuilder; -} - namespace ipower { class PowerEngine; } @@ -54,8 +49,8 @@ namespace ipnp { IREval() = default; ~IREval() = default; - void initIREval(idb::IdbBuilder* idb_builder, PNPConfig* pnp_config = nullptr); - void runIREval(idb::IdbBuilder* idb_builder); + void initIREval(); + void runIREval(); // getter double getMaxIRDrop() const; diff --git a/src/operation/iPNP/source/module/optimizer/CMakeLists.txt b/src/operation/iPNP/source/module/optimizer/CMakeLists.txt index 26ebf3b39d9bf3084bca4b0f88baff35847e8866..5e3bba3c13d1f86a0552f5556a8ca6a3b4c15822 100644 --- a/src/operation/iPNP/source/module/optimizer/CMakeLists.txt +++ b/src/operation/iPNP/source/module/optimizer/CMakeLists.txt @@ -1,12 +1,19 @@ include_directories(${HOME_PLATFORM}/data_manager) -add_library(optimizer +add_library(pnp-optimizer PdnOptimizer.cpp SimulatedAnnealing.cpp ) -target_link_libraries(optimizer +target_link_libraries(pnp-optimizer PUBLIC - evaluator - data_manager + pnp-evaluator + pnp-data + pnp-config + idm +) + +target_include_directories(pnp-optimizer + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} ) \ No newline at end of file diff --git a/src/operation/iPNP/source/module/optimizer/PdnOptimizer.cpp b/src/operation/iPNP/source/module/optimizer/PdnOptimizer.cpp index 41f8488306b4a7ba24d169fb1919b219943bed6b..7a57f5cfd95a68f783378650504a336c22d000a6 100644 --- a/src/operation/iPNP/source/module/optimizer/PdnOptimizer.cpp +++ b/src/operation/iPNP/source/module/optimizer/PdnOptimizer.cpp @@ -24,93 +24,87 @@ #include "PdnOptimizer.hh" -#include "SimulatedAnnealing.hh" +#include "PNP.hh" #include "PNPConfig.hh" -#include "iPNPApi.hh" -#include "iPNP.hh" +#include "SimulatedAnnealing.hh" +#include "idm.h" #include "log/Log.hh" namespace ipnp { - PdnOptimizer::PdnOptimizer() - : _opt_score(0.0) - { - PNPConfig* temp_config = new PNPConfig(); - if (temp_config->get_sa_initial_temp() && - temp_config->get_sa_cooling_rate() && - temp_config->get_sa_min_temp() && - temp_config->get_sa_iterations_per_temp() && - temp_config->get_sa_ir_drop_weight() && - temp_config->get_sa_overflow_weight()) - { - _initial_temp = temp_config->get_sa_initial_temp(); - _cooling_rate = temp_config->get_sa_cooling_rate(); - _min_temp = temp_config->get_sa_min_temp(); - _iterations_per_temp = temp_config->get_sa_iterations_per_temp(); - _ir_drop_weight = temp_config->get_sa_ir_drop_weight(); - _overflow_weight = temp_config->get_sa_overflow_weight(); - } else { - _initial_temp = 100.0; - _cooling_rate = 0.95; - _min_temp = 0.1; - _iterations_per_temp = 10; - _ir_drop_weight = 0.6; - _overflow_weight = 0.4; - LOG_WARNING << "iPNP instance not found, using default simulated annealing parameters."; - } - delete temp_config; - } - - PdnOptimizer::~PdnOptimizer() - { - } - - - void PdnOptimizer::optimize(GridManager initial_pdn, idb::IdbBuilder* idb_builder) - { - // TODO: Implement the two-stage PDN optimization process - } - - void PdnOptimizer::optimizeGlobal(GridManager initial_pdn, idb::IdbBuilder* idb_builder) - { - _input_pdn_grid = initial_pdn; - LOG_INFO << "Starting global optimization..." << std::endl; - LOG_INFO << "Simulated Annealing parameters: "; - LOG_INFO << " Initial temperature: " << _initial_temp; - LOG_INFO << " Cooling rate: " << _cooling_rate; - LOG_INFO << " Minimum temperature: " << _min_temp; - LOG_INFO << " Iterations per temperature: " << _iterations_per_temp; - LOG_INFO << " IR drop weight: " << _ir_drop_weight; - LOG_INFO << " Overflow weight: " << _overflow_weight; - - SimulatedAnnealing sa(_initial_temp, _cooling_rate, _min_temp, _iterations_per_temp, _ir_drop_weight, _overflow_weight); - - OptimizationResult result = sa.optimize(_input_pdn_grid, idb_builder); - - _output_pdn_grid = result.best_grid; - _opt_score = result.best_cost; - _region_data = result.region_data; - - LOG_INFO << "Global optimization complete. Score: " << _opt_score; - } - - void PdnOptimizer::optimizeByRegion(GridManager initial_pdn, idb::IdbBuilder* idb_builder) - { - // TODO: Implement region-based PDN optimization process - } - - void PdnOptimizer::setWeights(double ir_drop_weight, double overflow_weight) - { - _ir_drop_weight = ir_drop_weight; - _overflow_weight = overflow_weight; - } - - void PdnOptimizer::setAnnealingParams(double initial_temp, double cooling_rate, double min_temp, int iterations_per_temp) - { - _initial_temp = initial_temp; - _cooling_rate = cooling_rate; - _min_temp = min_temp; - _iterations_per_temp = iterations_per_temp; - } +PdnOptimizer::PdnOptimizer() + : _opt_score(0.0), + _initial_temp(100.0), + _cooling_rate(0.95), + _min_temp(0.1), + _iterations_per_temp(10), + _ir_drop_weight(0.6), + _overflow_weight(0.4) +{ +} + +PdnOptimizer::~PdnOptimizer() +{ +} + +void PdnOptimizer::optimize(PNPGridManager initial_pdn) +{ + // TODO: Implement the two-stage PDN optimization process +} + +void PdnOptimizer::optimizeGlobal(PNPGridManager initial_pdn) +{ + _input_pdn_grid = initial_pdn; + + _initial_temp = pnpConfig->get_sa_initial_temp(); + + _cooling_rate = pnpConfig->get_sa_cooling_rate(); + + _min_temp = pnpConfig->get_sa_min_temp(); + + _iterations_per_temp = pnpConfig->get_sa_iterations_per_temp(); + + _ir_drop_weight = pnpConfig->get_sa_ir_drop_weight(); + + _overflow_weight = pnpConfig->get_sa_overflow_weight(); + + LOG_INFO << "Starting global optimization..." << std::endl; + LOG_INFO << "Simulated Annealing parameters: "; + LOG_INFO << " Initial temperature: " << _initial_temp; + LOG_INFO << " Cooling rate: " << _cooling_rate; + LOG_INFO << " Minimum temperature: " << _min_temp; + LOG_INFO << " Iterations per temperature: " << _iterations_per_temp; + LOG_INFO << " IR drop weight: " << _ir_drop_weight; + LOG_INFO << " Overflow weight: " << _overflow_weight; + + SimulatedAnnealing sa(_initial_temp, _cooling_rate, _min_temp, _iterations_per_temp, _ir_drop_weight, _overflow_weight); + + OptimizationResult result = sa.optimize(_input_pdn_grid); + + _output_pdn_grid = result.best_grid; + _opt_score = result.best_cost; + _region_data = result.region_data; + + LOG_INFO << "Global optimization complete. Score: " << _opt_score; +} + +void PdnOptimizer::optimizeByRegion(PNPGridManager initial_pdn) +{ + // TODO: Implement region-based PDN optimization process +} + +void PdnOptimizer::setWeights(double ir_drop_weight, double overflow_weight) +{ + _ir_drop_weight = ir_drop_weight; + _overflow_weight = overflow_weight; +} + +void PdnOptimizer::setAnnealingParams(double initial_temp, double cooling_rate, double min_temp, int iterations_per_temp) +{ + _initial_temp = initial_temp; + _cooling_rate = cooling_rate; + _min_temp = min_temp; + _iterations_per_temp = iterations_per_temp; +} } // namespace ipnp diff --git a/src/operation/iPNP/source/module/optimizer/PdnOptimizer.hh b/src/operation/iPNP/source/module/optimizer/PdnOptimizer.hh index 84f0541a9c75395ba495ced637cf5a5c39e4cbf0..34121bdce94993bb448a27da23a503cf0cc22117 100644 --- a/src/operation/iPNP/source/module/optimizer/PdnOptimizer.hh +++ b/src/operation/iPNP/source/module/optimizer/PdnOptimizer.hh @@ -31,77 +31,55 @@ #include "CongestionEval.hh" #include "FastPlacer.hh" -#include "GridManager.hh" #include "IREval.hh" - -namespace idb { - class IdbLayer; - class IdbSpecialWireSegment; - class IdbRegularWireSegment; - class IdbBlockageList; - class IdbInstance; - class IdbRect; - class IdbVia; - class IdbLayerCut; - class IdbPin; - class IdbSpecialNet; - class IdbLayerRouting; - class IdbSpecialWire; - - enum class SegmentType : int8_t; - enum class IdbWireShapeType : uint8_t; - enum class IdbOrient : uint8_t; - - template - class IdbCoordinate; -} // namespace idb +#include "PNPGridManager.hh" namespace ipnp { - struct RegionData; - struct OptimizationResult; +struct RegionData; +struct OptimizationResult; - class PdnOptMethod - { - public: - virtual ~PdnOptMethod() = default; - }; +class PdnOptMethod +{ + public: + virtual ~PdnOptMethod() = default; +}; - class SimulatedAnnealing; +class SimulatedAnnealing; - class PdnOptimizer - { - public: - PdnOptimizer(); - ~PdnOptimizer(); +class PdnOptimizer +{ + public: + PdnOptimizer(); + ~PdnOptimizer(); - // getter - GridManager get_out_put_grid() { return _output_pdn_grid; } - double get_opt_score() const { return _opt_score; } + // getter + PNPGridManager get_out_put_grid() { return _output_pdn_grid; } + double get_opt_score() const { return _opt_score; } - void optimize(GridManager initial_pdn, idb::IdbBuilder* idb_builder); + void optimize(PNPGridManager initial_pdn); - void optimizeGlobal(GridManager initial_pdn, idb::IdbBuilder* idb_builder); + void optimizeGlobal(PNPGridManager initial_pdn); - void optimizeByRegion(GridManager initial_pdn, idb::IdbBuilder* idb_builder); + void optimizeByRegion(PNPGridManager initial_pdn); - void setWeights(double ir_drop_weight, double overflow_weight); + void setWeights(double ir_drop_weight, double overflow_weight); - void setAnnealingParams(double initial_temp, double cooling_rate, double min_temp, int iterations_per_temp); + void setAnnealingParams(double initial_temp, double cooling_rate, double min_temp, int iterations_per_temp); - private: - GridManager _input_pdn_grid; - GridManager _output_pdn_grid; - double _opt_score; - std::vector>> _region_data; + private: + PNPGridManager _input_pdn_grid; + PNPGridManager _output_pdn_grid; + double _opt_score; + std::vector>> _region_data; - double _initial_temp; - double _cooling_rate; - double _min_temp; - int _iterations_per_temp; + double _initial_temp; + double _cooling_rate; + double _min_temp; + int _iterations_per_temp; - double _ir_drop_weight; - double _overflow_weight; - }; + double _ir_drop_weight; + double _overflow_weight; +}; } // namespace ipnp diff --git a/src/operation/iPNP/source/module/optimizer/SimulatedAnnealing.cpp b/src/operation/iPNP/source/module/optimizer/SimulatedAnnealing.cpp index 8717f1c41b77213debb67aebfcd1626fd2d4946e..47d1a90eee2617680187b23e72f9aa18a4f7bcac 100644 --- a/src/operation/iPNP/source/module/optimizer/SimulatedAnnealing.cpp +++ b/src/operation/iPNP/source/module/optimizer/SimulatedAnnealing.cpp @@ -23,313 +23,424 @@ */ #include "SimulatedAnnealing.hh" -#include "iPNPIdbWrapper.hh" -#include "PNPConfig.hh" -namespace ipnp { - SimulatedAnnealing::SimulatedAnnealing(double initial_temp, double cooling_rate, - double min_temp, int iterations_per_temp, double ir_drop_weight, double overflow_weight) - : _initial_temp(initial_temp), - _cooling_rate(cooling_rate), - _min_temp(min_temp), - _iterations_per_temp(iterations_per_temp), - _max_no_improvement(20), - _ir_drop_weight(ir_drop_weight), - _overflow_weight(overflow_weight), - _max_ir_drop(std::numeric_limits::min()), - _min_ir_drop(std::numeric_limits::max()), - _max_overflow(std::numeric_limits::min()), - _min_overflow(std::numeric_limits::max()) - { - std::random_device rd; - _rng = std::mt19937(rd()); - } +#include +#include +#include +#include - OptimizationResult SimulatedAnnealing::optimize(const GridManager& initial_grid, idb::IdbBuilder* idb_builder) - { - GridManager current_solution = initial_grid; - GridManager best_solution = current_solution; - - CostResult current_result = evaluateCost(current_solution, current_solution, idb_builder); - double current_cost = current_result.cost; - double best_cost = current_cost; - - LOG_INFO << "Initial solution: " << std::endl - << " IR Drop: " << current_result.ir_drop - << ", Normalized IR: " << current_result.normalized_ir_drop - << ", Overflow: " << current_result.overflow - << ", Normalized OF: " << current_result.normalized_overflow - << ", Total Cost: " << current_cost - << " (IR weight:" << _ir_drop_weight << ", OF weight:" << _overflow_weight << ")" << std::endl; - - double temperature = _initial_temp; - int no_improvement_count = 0; - int total_iterations = 0; - - // Outer loop - while (!shouldTerminate(total_iterations, temperature, no_improvement_count)) { - // Inner loop - for (int i = 0; i < _iterations_per_temp; i++) { - // Generate neighboring solution - GridManager new_solution = generateNeighbor(current_solution); - - // Evaluate new solution - CostResult new_result = evaluateCost(new_solution, current_solution, idb_builder); - double new_cost = new_result.cost; - - LOG_INFO << "Iter[" << total_iterations << "] Temp[" << temperature << "]"; - LOG_INFO << " IR Drop: " << new_result.ir_drop; - LOG_INFO << " Normalized IR: " << new_result.normalized_ir_drop; - LOG_INFO << " Overflow: " << new_result.overflow; - LOG_INFO << " Normalized OF: " << new_result.normalized_overflow; - LOG_INFO << " Total Cost: " << new_cost; - LOG_INFO << " IR weight:" << _ir_drop_weight << ", OF weight:" << _overflow_weight; - - // Acceptance criteria - if (acceptSolution(current_cost, new_cost, temperature)) { - current_solution = new_solution; - current_cost = new_cost; - - // Save to IDB only after accepting the solution - iPNPIdbWrapper wrapper; - wrapper.set_idb_design(idb_builder->get_def_service()->get_design()); - wrapper.set_idb_builder(idb_builder); - wrapper.saveToIdb(current_solution); - - LOG_INFO << " Solution ACCEPTED! New current cost: " << current_cost << std::endl; - - // Update global best solution - if (new_cost < best_cost) { - best_solution = new_solution; - best_cost = new_cost; - no_improvement_count = 0; - LOG_INFO << " NEW BEST SOLUTION! Cost: " << best_cost << std::endl; - LOG_INFO << " IR Drop: " << new_result.ir_drop << std::endl; - LOG_INFO << " Overflow: " << new_result.overflow << std::endl; - } - else { - LOG_INFO << " Solution accepted but not better than best. No change to best solution." << current_cost << std::endl; - no_improvement_count++; - } - } - else { - no_improvement_count++; - } +#include +#include - total_iterations++; - } - - // Cooling - temperature *= _cooling_rate; - LOG_INFO << "===== Temperature: " << temperature - << ", Current cost: " << current_cost - << ", Best cost so far: " << best_cost - << ", No improvement count: " << no_improvement_count << " =====" << std::endl; - - - LOG_INFO << "Temperature: " << temperature << ", Best cost: " << best_cost; - } +#include "PNPConfig.hh" +#include "PNPIdbWrapper.hh" +#include "idm.h" - // Return optimization results - OptimizationResult result; - result.best_grid = best_solution; - result.best_cost = best_cost; +namespace ipnp { - return result; +SimulatedAnnealing::SimulatedAnnealing(double initial_temp, double cooling_rate, double min_temp, int iterations_per_temp, + double ir_drop_weight, double overflow_weight) + : _initial_temp(initial_temp), + _cooling_rate(cooling_rate), + _min_temp(min_temp), + _iterations_per_temp(iterations_per_temp), + _max_no_improvement(20), + _ir_drop_weight(ir_drop_weight), + _overflow_weight(overflow_weight), + _max_ir_drop(std::numeric_limits::min()), + _min_ir_drop(std::numeric_limits::max()), + _max_overflow(std::numeric_limits::min()), + _min_overflow(std::numeric_limits::max()) +{ + std::random_device rd; + _rng = std::mt19937(rd()); +} + +// Helper function to create directories +bool create_directories(const std::string& path) +{ + size_t pos = 0; + std::string dir; + int ret = 0; + + if (path[0] == '/') { + pos = 1; } - GridManager SimulatedAnnealing::generateNeighbor(const GridManager& current) - { - GridManager neighbor = current; - - int modifiable_min_layer; - int modifiable_max_layer; - - PNPConfig* temp_config = new PNPConfig(); - if (temp_config->get_sa_modifiable_layer_min() && temp_config->get_sa_modifiable_layer_max()) { - modifiable_min_layer = temp_config->get_sa_modifiable_layer_min(); - modifiable_max_layer = temp_config->get_sa_modifiable_layer_max(); - } - else { - modifiable_min_layer = 3; - modifiable_max_layer = 6; - } - delete temp_config; - - // Use configured range to generate random layer - std::uniform_int_distribution layer_dist(modifiable_min_layer, modifiable_max_layer); - std::uniform_int_distribution row_dist(0, current.get_ho_region_num() - 1); - std::uniform_int_distribution col_dist(0, current.get_ver_region_num() - 1); - - int layer = layer_dist(_rng); - int row = row_dist(_rng); - int col = col_dist(_rng); - - // Get current template information - const auto& old_template = current.get_template_data()[layer][row][col]; - - // Print current template information - LOG_INFO << "Attempting to change template at: Layer M" << current.get_power_layers()[layer] - << " (idx:" << layer << "), Region[" << row << "][" << col << "]" << std::endl; - LOG_INFO << " Old template information: " << std::endl; - if (old_template.get_direction() == StripeDirection::kHorizontal) { - LOG_INFO << "direction: Horizontal" << std::endl; - } - else { - LOG_INFO << "direction: Vertical" << std::endl; - } - LOG_INFO << "width: " << old_template.get_width() << std::endl; - LOG_INFO << "pg_offset: " << old_template.get_pg_offset() << std::endl; - LOG_INFO << "space: " << old_template.get_space() << std::endl; - LOG_INFO << "offset: " << old_template.get_offset() << std::endl; - - - SingleTemplate new_template; - std::vector vertical_templates = current.get_vertical_templates(); - std::vector horizontal_templates = current.get_horizontal_templates(); - - // Randomly select a new template - bool is_vertical = (layer % 2 == 0); // M9 has index 0, which is even, so it's Vertical - if (is_vertical) { - size_t old_idx = 0; - for (size_t i = 0; i < vertical_templates.size(); i++) { - if (isSameTemplate(old_template, vertical_templates[i])) { - old_idx = i; - break; - } - } - std::uniform_int_distribution template_dist(0, vertical_templates.size() - 2); - size_t template_idx = template_dist(_rng); - if (template_idx >= old_idx) { - template_idx++; - } - new_template = vertical_templates[template_idx]; - } - else { - size_t old_idx = 0; - bool found = false; - for (size_t i = 0; i < horizontal_templates.size(); i++) { - if (isSameTemplate(old_template, horizontal_templates[i])) { - old_idx = i; - found = true; - break; - } - } - std::uniform_int_distribution template_dist(0, horizontal_templates.size() - 2); - size_t template_idx = template_dist(_rng); - if (found && template_idx >= old_idx) { - template_idx++; - } - new_template = horizontal_templates[template_idx]; - } + while ((pos = path.find('/', pos)) != std::string::npos) { + dir = path.substr(0, pos++); + if (dir.empty()) + continue; - // Print new template information - LOG_INFO << "New template information: " << std::endl; - if (new_template.get_direction() == StripeDirection::kHorizontal) { - LOG_INFO << "direction: Horizontal" << std::endl; + ret = mkdir(dir.c_str(), 0755); + if (ret != 0 && errno != EEXIST) { + return false; } - else { - LOG_INFO << "direction: Vertical" << std::endl; - } - LOG_INFO << "width: " << new_template.get_width() << std::endl; - LOG_INFO << "pg_offset: " << new_template.get_pg_offset() << std::endl; - LOG_INFO << "space: " << new_template.get_space() << std::endl; - LOG_INFO << "offset: " << new_template.get_offset() << std::endl; - - neighbor.set_single_template(layer, row, col, new_template); - return neighbor; } + return true; +} - CostResult SimulatedAnnealing::evaluateCost(const GridManager& new_solution, const GridManager& current_solution, idb::IdbBuilder* idb_builder) - { +OptimizationResult SimulatedAnnealing::optimize(const PNPGridManager& initial_grid) +{ + PNPGridManager current_solution = initial_grid; + PNPGridManager best_solution = current_solution; - iPNPIdbWrapper temp_wrapper; - temp_wrapper.set_idb_design(idb_builder->get_def_service()->get_design()); - temp_wrapper.set_idb_builder(idb_builder); - temp_wrapper.saveToIdb(new_solution); + CostResult current_result = evaluateCost(current_solution, current_solution); + double current_cost = current_result.cost; + double best_cost = current_cost; - _cong_eval.evalEGR(idb_builder); - int32_t overflow = _cong_eval.get_total_overflow_union(); - - _ir_eval.runIREval(idb_builder); - double max_ir_drop = _ir_eval.getMaxIRDrop(); - double min_ir_drop = _ir_eval.getMinIRDrop(); - double avg_ir_drop = _ir_eval.getAvgIRDrop(); + // Get report_path directory from config + std::string report_path = "SA_report.txt"; - double normalized_ir_drop = normalizeIRDrop(max_ir_drop, min_ir_drop, avg_ir_drop); - double normalized_overflow = normalizeOverflow(overflow); - double cost = _ir_drop_weight * normalized_ir_drop + _overflow_weight * normalized_overflow; + // Use the passed config object - // New solution not yet accepted, restore current solution - temp_wrapper.saveToIdb(current_solution); + std::string dir_path = pnpConfig->get_report_path(); - return { cost, max_ir_drop, overflow, normalized_ir_drop, normalized_overflow }; + if (dir_path.back() != '/') { + dir_path += '/'; } - bool SimulatedAnnealing::acceptSolution(double current_cost, double new_cost, double temp) - { - if (new_cost < current_cost) { - return true; - } + report_path = dir_path + "SA_report.txt"; + LOG_INFO << "Using directory from config for SA report: " << dir_path << std::endl; - // Calculate acceptance probability according to Metropolis criterion - // Probability formula: P = exp(-ΔE/T), where ΔE is the cost difference and T is the current temperature - // Higher temperature = higher probability of accepting worse solutions; lower temperature = more likely to only accept better solutions - double delta = new_cost - current_cost; - double acceptance_probability = std::exp(-delta / temp); + LOG_INFO << "Report will be written to: " << report_path << std::endl; - // Accept new solution if random number is less than acceptance probability - std::uniform_real_distribution dist(0.0, 1.0); - return dist(_rng) < acceptance_probability; + // Ensure the directory for the report file exists + std::string directory = report_path.substr(0, report_path.find_last_of('/')); + if (!directory.empty()) { + if (!create_directories(directory)) { + LOG_ERROR << "Failed to create directory: " << directory << ", error: " << strerror(errno) << std::endl; + } else { + LOG_INFO << "Directory ensured: " << directory << std::endl; + } } - bool SimulatedAnnealing::shouldTerminate(int iterations, double temp, int no_improvement_count) - { - // Temperature below threshold - if (temp < _min_temp) return true; + // Check if the file exists + struct stat buffer; + bool file_exists = (stat(report_path.c_str(), &buffer) == 0); - // Multiple consecutive iterations with no improvement - if (no_improvement_count > _max_no_improvement) return true; + if (file_exists) { + LOG_INFO << "Report file already exists, will overwrite it" << std::endl; + } else { + LOG_INFO << "Report file does not exist, will create it" << std::endl; + } - return false; + // Open report file for writing with explicit mode + std::ofstream report_file(report_path.c_str(), std::ios::out | std::ios::trunc); + if (!report_file.is_open()) { + LOG_ERROR << "Failed to open report file for writing: " << report_path << ", error: " << strerror(errno) << std::endl; + return {best_solution, best_cost}; + } else { + LOG_INFO << "Successfully opened report file for writing" << std::endl; } - double SimulatedAnnealing::normalizeIRDrop(double max_ir_drop, double min_ir_drop, double avg_ir_drop) - { - _max_ir_drop = std::max(_max_ir_drop, max_ir_drop); - _min_ir_drop = std::min(_min_ir_drop, min_ir_drop); + // Set formatting for floating point numbers + report_file << std::fixed << std::setprecision(6); + + // Write header and initial solution information + report_file << "======================================================================" << std::endl; + report_file << " SIMULATED ANNEALING REPORT " << std::endl; + report_file << "======================================================================" << std::endl; + report_file << std::endl; + report_file << "INITIAL SOLUTION:" << std::endl; + report_file << " IR Drop : " << std::setw(12) << current_result.ir_drop << std::endl; + report_file << " Normalized IR : " << std::setw(12) << current_result.normalized_ir_drop << std::endl; + report_file << " Overflow : " << std::setw(12) << current_result.overflow << std::endl; + report_file << " Normalized OF : " << std::setw(12) << current_result.normalized_overflow << std::endl; + report_file << " Total Cost : " << std::setw(12) << current_cost << std::endl; + report_file << " IR Weight : " << std::setw(12) << _ir_drop_weight << std::endl; + report_file << " Overflow Weight : " << std::setw(12) << _overflow_weight << std::endl; + report_file << std::endl; + report_file << "----------------------------------------------------------------------" << std::endl; + report_file << std::endl; + + LOG_INFO << "Initial solution: " << std::endl + << " IR Drop: " << current_result.ir_drop << ", Normalized IR: " << current_result.normalized_ir_drop + << ", Overflow: " << current_result.overflow << ", Normalized OF: " << current_result.normalized_overflow + << ", Total Cost: " << current_cost << " (IR weight:" << _ir_drop_weight << ", OF weight:" << _overflow_weight << ")" + << std::endl; + + double temperature = _initial_temp; + int no_improvement_count = 0; + int total_iterations = 0; + + // Outer loop + while (!shouldTerminate(total_iterations, temperature, no_improvement_count)) { + // Inner loop + for (int i = 0; i < _iterations_per_temp; i++) { + // Generate neighboring solution + PNPGridManager new_solution = generateNeighbor(current_solution); + + // Evaluate new solution + CostResult new_result = evaluateCost(new_solution, current_solution); + double new_cost = new_result.cost; + + // Write iteration information to report file + report_file << "ITERATION: " << std::setw(5) << total_iterations << " | TEMPERATURE: " << std::setw(12) << temperature << std::endl; + report_file << " IR Drop : " << std::setw(12) << new_result.ir_drop << std::endl; + report_file << " Normalized IR : " << std::setw(12) << new_result.normalized_ir_drop << std::endl; + report_file << " Overflow : " << std::setw(12) << new_result.overflow << std::endl; + report_file << " Normalized OF : " << std::setw(12) << new_result.normalized_overflow << std::endl; + report_file << " Total Cost : " << std::setw(12) << new_cost << std::endl; + + LOG_INFO << "Iter[" << total_iterations << "] Temp[" << temperature << "]"; + LOG_INFO << " IR Drop: " << new_result.ir_drop; + LOG_INFO << " Normalized IR: " << new_result.normalized_ir_drop; + LOG_INFO << " Overflow: " << new_result.overflow; + LOG_INFO << " Normalized OF: " << new_result.normalized_overflow; + LOG_INFO << " Total Cost: " << new_cost; + LOG_INFO << " IR weight:" << _ir_drop_weight << ", OF weight:" << _overflow_weight; + + // Acceptance criteria + if (acceptSolution(current_cost, new_cost, temperature)) { + current_solution = new_solution; + current_cost = new_cost; + + // Save to IDB only after accepting the solution + PNPIdbWrapper wrapper; + wrapper.saveToIdb(current_solution); + // wrapper.writeIdbToDef("/home/sujianrong/iEDA/src/operation/iPNP/data/case/s9234/result/debug.def"); + + LOG_INFO << " Solution ACCEPTED! New current cost: " << current_cost << std::endl; + report_file << " STATUS : ACCEPTED" << std::endl; + report_file << " New Current Cost : " << std::setw(12) << current_cost << std::endl; + + // Update global best solution + if (new_cost < best_cost) { + best_solution = new_solution; + best_cost = new_cost; + no_improvement_count = 0; + LOG_INFO << " NEW BEST SOLUTION! Cost: " << best_cost << std::endl; + LOG_INFO << " IR Drop: " << new_result.ir_drop << std::endl; + LOG_INFO << " Overflow: " << new_result.overflow << std::endl; + + report_file << " BEST SOLUTION : YES" << std::endl; + report_file << " Best Cost : " << std::setw(12) << best_cost << std::endl; + } else { + LOG_INFO << " Solution accepted but not better than best. No change to best solution." << current_cost << std::endl; + report_file << " BEST SOLUTION : NO" << std::endl; + no_improvement_count++; + } + } else { + report_file << " STATUS : REJECTED" << std::endl; + no_improvement_count++; + } - // Min-Max normalization to [0,1] range - if (_max_ir_drop - _min_ir_drop < 1e-10) { - return 0.0; // Avoid division by near-zero value + report_file << "----------------------------------------------------------------------" << std::endl; + report_file << std::endl; + + total_iterations++; } - return (avg_ir_drop - _min_ir_drop) / (_max_ir_drop - _min_ir_drop); - } - double SimulatedAnnealing::normalizeOverflow(int32_t overflow) - { - _max_overflow = std::max(_max_overflow, overflow); - _min_overflow = std::min(_min_overflow, overflow); + // Cooling + temperature *= _cooling_rate; + LOG_INFO << "===== Temperature: " << temperature << ", Current cost: " << current_cost << ", Best cost so far: " << best_cost + << ", No improvement count: " << no_improvement_count << " =====" << std::endl; + + report_file << "=====================================================================" << std::endl; + report_file << "TEMPERATURE UPDATE: " << std::setw(12) << temperature << std::endl; + report_file << " Current Cost : " << std::setw(12) << current_cost << std::endl; + report_file << " Best Cost : " << std::setw(12) << best_cost << std::endl; + report_file << " No Improvement : " << std::setw(12) << no_improvement_count << std::endl; + report_file << "=====================================================================" << std::endl; + report_file << std::endl; - // Min-Max normalization to [0,1] range - if (_max_overflow - _min_overflow < 1e-10) { - if (_max_overflow == _min_overflow && _max_overflow != 0) { - // Only one non-zero sample point, return a middle value of 0.5 - return 0.5; + LOG_INFO << "Temperature: " << temperature << ", Best cost: " << best_cost; + } + + // Write final results + report_file << "======================================================================" << std::endl; + report_file << " FINAL OPTIMIZATION RESULTS " << std::endl; + report_file << "======================================================================" << std::endl; + report_file << " Best Cost : " << std::setw(12) << best_cost << std::endl; + report_file << " Total Iterations : " << std::setw(12) << total_iterations << std::endl; + report_file << " Final Temperature: " << std::setw(12) << temperature << std::endl; + report_file << "======================================================================" << std::endl; + + // Close file + report_file.close(); + + // Return optimization results + OptimizationResult result; + result.best_grid = best_solution; + result.best_cost = best_cost; + + return result; +} + +PNPGridManager SimulatedAnnealing::generateNeighbor(const PNPGridManager& current) +{ + PNPGridManager neighbor = current; + + int modifiable_min_layer = pnpConfig->get_sa_modifiable_layer_min(); + int modifiable_max_layer = pnpConfig->get_sa_modifiable_layer_max(); + + // Use configured range to generate random layer + std::uniform_int_distribution layer_dist(modifiable_min_layer, modifiable_max_layer); + std::uniform_int_distribution row_dist(0, current.get_ho_region_num() - 1); + std::uniform_int_distribution col_dist(0, current.get_ver_region_num() - 1); + + int layer = layer_dist(_rng); + int row = row_dist(_rng); + int col = col_dist(_rng); + + // Get current template information + const auto& old_template = current.get_template_data()[layer][row][col]; + + // Print current template information + LOG_INFO << "Attempting to change template at: Layer M" << current.get_power_layers()[layer] << " (idx:" << layer << "), Region[" << row + << "][" << col << "]" << std::endl; + LOG_INFO << " Old template information: " << std::endl; + if (old_template.get_direction() == StripeDirection::kHorizontal) { + LOG_INFO << "direction: Horizontal" << std::endl; + } else { + LOG_INFO << "direction: Vertical" << std::endl; + } + LOG_INFO << "width: " << old_template.get_width() << std::endl; + LOG_INFO << "pg_offset: " << old_template.get_pg_offset() << std::endl; + LOG_INFO << "space: " << old_template.get_space() << std::endl; + LOG_INFO << "offset: " << old_template.get_offset() << std::endl; + + SingleTemplate new_template; + std::vector vertical_templates = current.get_vertical_templates(); + std::vector horizontal_templates = current.get_horizontal_templates(); + + // Randomly select a new template + bool is_vertical = (layer % 2 == 0); // M9 has index 0, which is even, so it's Vertical + if (is_vertical) { + size_t old_idx = 0; + for (size_t i = 0; i < vertical_templates.size(); i++) { + if (isSameTemplate(old_template, vertical_templates[i])) { + old_idx = i; + break; + } + } + std::uniform_int_distribution template_dist(0, vertical_templates.size() - 2); + size_t template_idx = template_dist(_rng); + if (template_idx >= old_idx) { + template_idx++; + } + new_template = vertical_templates[template_idx]; + } else { + size_t old_idx = 0; + bool found = false; + for (size_t i = 0; i < horizontal_templates.size(); i++) { + if (isSameTemplate(old_template, horizontal_templates[i])) { + old_idx = i; + found = true; + break; } - return 0; // Avoid division by near-zero value } - return static_cast(overflow - _min_overflow) / static_cast(_max_overflow - _min_overflow); + std::uniform_int_distribution template_dist(0, horizontal_templates.size() - 2); + size_t template_idx = template_dist(_rng); + if (found && template_idx >= old_idx) { + template_idx++; + } + new_template = horizontal_templates[template_idx]; + } + + // Print new template information + LOG_INFO << "New template information: " << std::endl; + if (new_template.get_direction() == StripeDirection::kHorizontal) { + LOG_INFO << "direction: Horizontal" << std::endl; + } else { + LOG_INFO << "direction: Vertical" << std::endl; + } + LOG_INFO << "width: " << new_template.get_width() << std::endl; + LOG_INFO << "pg_offset: " << new_template.get_pg_offset() << std::endl; + LOG_INFO << "space: " << new_template.get_space() << std::endl; + LOG_INFO << "offset: " << new_template.get_offset() << std::endl; + + neighbor.set_single_template(layer, row, col, new_template); + return neighbor; +} + +CostResult SimulatedAnnealing::evaluateCost(const PNPGridManager& new_solution, const PNPGridManager& current_solution) +{ + PNPIdbWrapper temp_wrapper; + temp_wrapper.saveToIdb(new_solution); + + _cong_eval.evalEGR(); + int32_t overflow = _cong_eval.get_total_overflow_union(); + + _ir_eval.runIREval(); + double max_ir_drop = _ir_eval.getMaxIRDrop(); + double min_ir_drop = _ir_eval.getMinIRDrop(); + double avg_ir_drop = _ir_eval.getAvgIRDrop(); + + double normalized_ir_drop = normalizeIRDrop(max_ir_drop, min_ir_drop, avg_ir_drop); + double normalized_overflow = normalizeOverflow(overflow); + double cost = _ir_drop_weight * normalized_ir_drop + _overflow_weight * normalized_overflow; + + // New solution not yet accepted, restore current solution + temp_wrapper.saveToIdb(current_solution); + + return {cost, max_ir_drop, overflow, normalized_ir_drop, normalized_overflow}; +} + +bool SimulatedAnnealing::acceptSolution(double current_cost, double new_cost, double temp) +{ + if (new_cost < current_cost) { + return true; } - bool SimulatedAnnealing::isSameTemplate(const SingleTemplate& t1, const SingleTemplate& t2) - { - // Compare all key attributes of the two templates - return (t1.get_direction() == t2.get_direction() && - t1.get_width() == t2.get_width() && - t1.get_pg_offset() == t2.get_pg_offset() && - t1.get_space() == t2.get_space() && - t1.get_offset() == t2.get_offset()); + // Calculate acceptance probability according to Metropolis criterion + // Probability formula: P = exp(-ΔE/T), where ΔE is the cost difference and T is the current temperature + // Higher temperature = higher probability of accepting worse solutions; lower temperature = more likely to only accept better solutions + double delta = new_cost - current_cost; + double acceptance_probability = std::exp(-delta / temp); + + // Accept new solution if random number is less than acceptance probability + std::uniform_real_distribution dist(0.0, 1.0); + return dist(_rng) < acceptance_probability; +} + +bool SimulatedAnnealing::shouldTerminate(int iterations, double temp, int no_improvement_count) +{ + // Temperature below threshold + if (temp < _min_temp) + return true; + + // Multiple consecutive iterations with no improvement + if (no_improvement_count > _max_no_improvement) + return true; + + return false; +} + +double SimulatedAnnealing::normalizeIRDrop(double max_ir_drop, double min_ir_drop, double avg_ir_drop) +{ + _max_ir_drop = std::max(_max_ir_drop, max_ir_drop); + _min_ir_drop = std::min(_min_ir_drop, min_ir_drop); + + // Min-Max normalization to [0,1] range + if (_max_ir_drop - _min_ir_drop < 1e-10) { + return 0.0; // Avoid division by near-zero value + } + return (avg_ir_drop - _min_ir_drop) / (_max_ir_drop - _min_ir_drop); +} + +double SimulatedAnnealing::normalizeOverflow(int32_t overflow) +{ + _max_overflow = std::max(_max_overflow, overflow); + _min_overflow = std::min(_min_overflow, overflow); + + // Min-Max normalization to [0,1] range + if (_max_overflow - _min_overflow < 1e-10) { + if (_max_overflow == _min_overflow && _max_overflow != 0) { + // Only one non-zero sample point, return a middle value of 0.5 + return 0.5; + } + return 0; // Avoid division by near-zero value } + return static_cast(overflow - _min_overflow) / static_cast(_max_overflow - _min_overflow); +} + +bool SimulatedAnnealing::isSameTemplate(const SingleTemplate& t1, const SingleTemplate& t2) +{ + // Compare all key attributes of the two templates + return (t1.get_direction() == t2.get_direction() && t1.get_width() == t2.get_width() && t1.get_pg_offset() == t2.get_pg_offset() + && t1.get_space() == t2.get_space() && t1.get_offset() == t2.get_offset()); +} } // namespace ipnp \ No newline at end of file diff --git a/src/operation/iPNP/source/module/optimizer/SimulatedAnnealing.hh b/src/operation/iPNP/source/module/optimizer/SimulatedAnnealing.hh index a68b0498f4aac146249367e20fb12c2840e8af36..6789768d547baeee31ac303501a204bcbff0141c 100644 --- a/src/operation/iPNP/source/module/optimizer/SimulatedAnnealing.hh +++ b/src/operation/iPNP/source/module/optimizer/SimulatedAnnealing.hh @@ -22,87 +22,80 @@ * @date 2024-07-15 */ - // SimulatedAnnealing.hh +// SimulatedAnnealing.hh #pragma once +#include #include #include +#include #include #include -#include -#include -#include "GridManager.hh" -#include "IREval.hh" #include "CongestionEval.hh" - -namespace idb { - class IdbBuilder; -} +#include "IREval.hh" +#include "PNPGridManager.hh" namespace ipnp { - - - struct RegionData { - double ir_drop; - int32_t overflow; - }; - - struct OptimizationResult { - GridManager best_grid; - double best_cost; - std::vector>> region_data; // [layer][row][col] - }; - - struct CostResult { - double cost; - double ir_drop; - int32_t overflow; - double normalized_ir_drop; - double normalized_overflow; - }; - - class SimulatedAnnealing - { - public: - SimulatedAnnealing(double initial_temp, - double cooling_rate, - double min_temp, - int iterations_per_temp, - double ir_drop_weight, - double overflow_weight); - ~SimulatedAnnealing() = default; - - - OptimizationResult optimize(const GridManager& initial_grid, idb::IdbBuilder* idb_builder); - CostResult evaluateCost(const GridManager& new_solution, const GridManager& current_solution, idb::IdbBuilder* idb_builder); - - private: - CongestionEval _cong_eval; - IREval _ir_eval; - - double _initial_temp; - double _cooling_rate; - double _min_temp; - int _iterations_per_temp; - int _max_no_improvement; - - std::mt19937 _rng; - - double _ir_drop_weight; - double _overflow_weight; - - double _max_ir_drop; - double _min_ir_drop; - int32_t _max_overflow; - int32_t _min_overflow; - - GridManager generateNeighbor(const GridManager& current); - bool acceptSolution(double current_cost, double new_cost, double temp); - bool shouldTerminate(int iterations, double temp, int no_improvement_count); - double normalizeIRDrop(double max_ir_drop, double min_ir_drop, double avg_ir_drop); - double normalizeOverflow(int32_t overflow); - bool isSameTemplate(const SingleTemplate& t1, const SingleTemplate& t2); - }; + +struct RegionData +{ + double ir_drop; + int32_t overflow; +}; + +struct OptimizationResult +{ + PNPGridManager best_grid; + double best_cost; + std::vector>> region_data; // [layer][row][col] +}; + +struct CostResult +{ + double cost; + double ir_drop; + int32_t overflow; + double normalized_ir_drop; + double normalized_overflow; +}; + +class SimulatedAnnealing +{ + public: + SimulatedAnnealing(double initial_temp, double cooling_rate, double min_temp, int iterations_per_temp, double ir_drop_weight, + double overflow_weight); + ~SimulatedAnnealing() = default; + + OptimizationResult optimize(const PNPGridManager& initial_grid); + CostResult evaluateCost(const PNPGridManager& new_solution, const PNPGridManager& current_solution); + + private: + CongestionEval _cong_eval; + IREval _ir_eval; + + double _initial_temp; + double _cooling_rate; + double _min_temp; + int _iterations_per_temp; + int _max_no_improvement; + + std::mt19937 _rng; + + double _ir_drop_weight; + double _overflow_weight; + + double _max_ir_drop; + double _min_ir_drop; + int32_t _max_overflow; + int32_t _min_overflow; + + PNPGridManager generateNeighbor(const PNPGridManager& current); + bool acceptSolution(double current_cost, double new_cost, double temp); + bool shouldTerminate(int iterations, double temp, int no_improvement_count); + double normalizeIRDrop(double max_ir_drop, double min_ir_drop, double avg_ir_drop); + double normalizeOverflow(int32_t overflow); + bool isSameTemplate(const SingleTemplate& t1, const SingleTemplate& t2); +}; } // namespace ipnp diff --git a/src/operation/iPNP/source/module/tcl-cmd/CMakeLists.txt b/src/operation/iPNP/source/module/pnp-cmd/CMakeLists.txt similarity index 100% rename from src/operation/iPNP/source/module/tcl-cmd/CMakeLists.txt rename to src/operation/iPNP/source/module/pnp-cmd/CMakeLists.txt diff --git a/src/operation/iPNP/source/module/pnp-cmd/CmdAddVIA1.cc b/src/operation/iPNP/source/module/pnp-cmd/CmdAddVIA1.cc new file mode 100644 index 0000000000000000000000000000000000000000..8cb263feaf980f42b9b35ae84da263be72f5561e --- /dev/null +++ b/src/operation/iPNP/source/module/pnp-cmd/CmdAddVIA1.cc @@ -0,0 +1,78 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file CmdAddVIA1.cc + * @author Jianrong Su + * @brief Command to add VIA1 connections between M2 and M1 layers + * @version 1.0 + * @date 2025-06-30 + */ + +#include + +#include "PNP.hh" +#include "PNPShellCmd.hh" +#include "ipnp_api.hh" +#include "log/Log.hh" + +namespace ipnp { + +CmdAddVIA1::CmdAddVIA1(const char* cmd_name) : TclCmd(cmd_name) +{ + auto* config_option = new TclStringOption("-config", 0, ""); + addOption(config_option); +} + +unsigned CmdAddVIA1::check() +{ + TclOption* config_option = getOptionOrArg("-config"); + + if (config_option) { + auto* config_file = config_option->getStringVal(); + if (!std::filesystem::exists(config_file)) { + LOG_ERROR << "Configuration file not found: " << config_file; + return 0; + } + } + return 1; // check success +} + +unsigned CmdAddVIA1::exec() +{ + if (!check()) { + return 0; + } + + TclOption* config_option = getOptionOrArg("-config"); + + if (config_option) { + auto* config_file = config_option->getStringVal(); + + LOG_INFO << "Adding VIA1 connections between M2 and M1 layers with configuration: " << config_file; + + ipnp::PNPApi::connect_M2_M1(config_file); + + LOG_INFO << "VIA1 connections added successfully."; + } else { + LOG_ERROR << "Configuration file is required for adding VIA1 connections."; + return 0; + } + + return 1; +} + +} // namespace ipnp \ No newline at end of file diff --git a/src/operation/iPNP/source/module/tcl-cmd/CmdRunPnp.cc b/src/operation/iPNP/source/module/pnp-cmd/CmdRunPnp.cc similarity index 48% rename from src/operation/iPNP/source/module/tcl-cmd/CmdRunPnp.cc rename to src/operation/iPNP/source/module/pnp-cmd/CmdRunPnp.cc index fe2ad3ca338dc25d095ca18e187ecabd5a9bac2d..f3f877784ef01eae812f54c1f32e8683c2c34f7e 100644 --- a/src/operation/iPNP/source/module/tcl-cmd/CmdRunPnp.cc +++ b/src/operation/iPNP/source/module/pnp-cmd/CmdRunPnp.cc @@ -22,24 +22,24 @@ * @date 2025-06-30 */ -#include "ShellCmd.hh" -#include "log/Log.hh" -#include "iPNP.hh" -#include "iPNPApi.hh" #include #include -namespace ipnp { +#include "PNP.hh" +#include "PNPShellCmd.hh" +#include "ipnp_api.hh" +#include "log/Log.hh" -CmdRunPnp::CmdRunPnp(const char* cmd_name) : TclCmd(cmd_name) { +namespace ipnp { +CmdRunPnp::CmdRunPnp(const char* cmd_name) : TclCmd(cmd_name) +{ auto* config_option = new TclStringOption("-config", 0, ""); addOption(config_option); - } -unsigned CmdRunPnp::check() { - +unsigned CmdRunPnp::check() +{ TclOption* config_option = getOptionOrArg("-config"); if (config_option) { @@ -49,10 +49,11 @@ unsigned CmdRunPnp::check() { return 0; } } - return 1; // check success + return 1; // check success } -unsigned CmdRunPnp::exec() { +unsigned CmdRunPnp::exec() +{ if (!check()) { return 0; } @@ -61,47 +62,40 @@ unsigned CmdRunPnp::exec() { if (config_option) { auto* config_file = config_option->getStringVal(); - - if (iPNPApi::getInstance()) { - LOG_ERROR << "An existing iPNP instance was found. It will be replaced."; - delete iPNPApi::getInstance(); - iPNPApi::setInstance(nullptr); - } - - LOG_INFO << "Initializing iPNP with configuration: " << config_file; - auto* new_instance = new ipnp::iPNP(config_file); - iPNPApi::setInstance(new_instance); + + LOG_INFO << "Running iPNP with configuration: " << config_file; + + std::string start_info + = "\033[49;32m" + " _ ____ _ ______ ______________ ____ ______\n" + " (_) __ \\/ | / / __ \\ / ___/_ __/ | / __ \\/_ __/\n" + " / / /_/ / |/ / /_/ / \\__ \\ / / / /| | / /_/ / / / \n" + " / / ____/ /| / ____/ ___/ // / / ___ |/ _, _/ / / \n" + "/_/_/ /_/ |_/_/ /____//_/ /_/ |_/_/ |_| /_/ \n" + " \n" + "\e[0m"; + + std::cout << start_info << std::endl; + + ipnp::PNPApi::run_pnp(config_file); + + std::string finish_info + = "\033[49;32m" + " _ ____ _ ______ ___________ ___________ __ __\n" + " (_) __ \\/ | / / __ \\ / ____/ _/ | / / _/ ___// / / /\n" + " / / /_/ / |/ / /_/ / / /_ / // |/ // / \\__ \\/ /_/ / \n" + " / / ____/ /| / ____/ / __/ _/ // /| // / ___/ / __ / \n" + "/_/_/ /_/ |_/_/ /_/ /___/_/ |_/___//____/_/ /_/ \n" + " \n" + "\e[0m"; + + std::cout << finish_info << std::endl; + } else { + LOG_ERROR << "Configuration file is required for running iPNP."; + return 0; } - auto* ipnp = iPNPApi::getInstance(); - - std::string start_info = - "\033[49;32m" - " _ ____ _ ______ ______________ ____ ______\n" - " (_) __ \\/ | / / __ \\ / ___/_ __/ | / __ \\/_ __/\n" - " / / /_/ / |/ / /_/ / \\__ \\ / / / /| | / /_/ / / / \n" - " / / ____/ /| / ____/ ___/ // / / ___ |/ _, _/ / / \n" - "/_/_/ /_/ |_/_/ /____//_/ /_/ |_/_/ |_| /_/ \n" - " \n" - "\e[0m"; - - std::cout << start_info << std::endl; - - ipnp->run(); - - std::string finish_info = - "\033[49;32m" - " _ ____ _ ______ ___________ ___________ __ __\n" - " (_) __ \\/ | / / __ \\ / ____/ _/ | / / _/ ___// / / /\n" - " / / /_/ / |/ / /_/ / / /_ / // |/ // / \\__ \\/ /_/ / \n" - " / / ____/ /| / ____/ / __/ _/ // /| // / ___/ / __ / \n" - "/_/_/ /_/ |_/_/ /_/ /___/_/ |_/___//____/_/ /_/ \n" - " \n" - "\e[0m"; - - std::cout << finish_info << std::endl; - return 1; } -} // namespace ipnp \ No newline at end of file +} // namespace ipnp \ No newline at end of file diff --git a/src/operation/iPNP/source/module/pnp-cmd/PNPShellCmd.hh b/src/operation/iPNP/source/module/pnp-cmd/PNPShellCmd.hh new file mode 100644 index 0000000000000000000000000000000000000000..fe971d6b331d49cc1faf20f554cbd1395e6d2885 --- /dev/null +++ b/src/operation/iPNP/source/module/pnp-cmd/PNPShellCmd.hh @@ -0,0 +1,65 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file PNPShellCmd.hh + * @author Jianrong Su + * @brief + * @version 1.0 + * @date 2025-06-30 + */ + +#pragma once + +#include "ScriptEngine.hh" + +namespace ipnp { + + using ieda::ScriptEngine; + using ieda::TclCmd; + using ieda::TclCmds; + using ieda::TclDoubleListOption; + using ieda::TclDoubleOption; + using ieda::TclEncodeResult; + using ieda::TclIntListOption; + using ieda::TclIntOption; + using ieda::TclOption; + using ieda::TclStringListListOption; + using ieda::TclStringListOption; + using ieda::TclStringOption; + using ieda::TclSwitchOption; + + // Function to register commands + + class CmdRunPnp : public TclCmd { + public: + explicit CmdRunPnp(const char* cmd_name); + ~CmdRunPnp() override = default; + + unsigned check() override; + unsigned exec() override; + }; + + class CmdAddVIA1 : public TclCmd { + public: + explicit CmdAddVIA1(const char* cmd_name); + ~CmdAddVIA1() override = default; + + unsigned check() override; + unsigned exec() override; + }; + +} // namespace ipnp diff --git a/src/operation/iPNP/source/module/synthesis/CMakeLists.txt b/src/operation/iPNP/source/module/synthesis/CMakeLists.txt index 4723e7957c7f3387de944618710ee9f5163ef734..c68d864d0a03c1df86656e11afb3771032ec0437 100644 --- a/src/operation/iPNP/source/module/synthesis/CMakeLists.txt +++ b/src/operation/iPNP/source/module/synthesis/CMakeLists.txt @@ -1,7 +1,23 @@ include_directories(${HOME_PLATFORM}/data_manager) -add_library(synthesis +add_library(pnp-synthesis NetworkSynthesis.cpp PowerRouter.cpp PowerVia.cpp -) \ No newline at end of file +) + +target_link_libraries(pnp-synthesis + PUBLIC + pnp-config + idb + idm + pnp-data + log +) + +target_include_directories(pnp-synthesis + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +set(CMAKE_BUILD_TYPE "debug") \ No newline at end of file diff --git a/src/operation/iPNP/source/module/synthesis/NetworkSynthesis.cpp b/src/operation/iPNP/source/module/synthesis/NetworkSynthesis.cpp index d95124000826121f3964c240b69548571cf67c6d..b56a9339003e135741e4ebde33e4b1b93ff51fba 100644 --- a/src/operation/iPNP/source/module/synthesis/NetworkSynthesis.cpp +++ b/src/operation/iPNP/source/module/synthesis/NetworkSynthesis.cpp @@ -32,14 +32,17 @@ #include #include +#include "IdbLayer.h" +#include "IdbSpecialNet.h" +#include "IdbSpecialWire.h" +#include "IdbVias.h" +#include "Log.hh" #include "idm.h" namespace ipnp { -NetworkSynthesis::NetworkSynthesis(SysnType sysn_type, GridManager grid_info) - : _network_sys_type(sysn_type), - _input_grid_info(grid_info), - _synthesized_network(grid_info) +NetworkSynthesis::NetworkSynthesis(SysnType sysn_type, PNPGridManager grid_info) + : _network_sys_type(sysn_type), _input_grid_info(grid_info), _synthesized_network(grid_info) { // initialize the synthesized network _synthesized_network.set_power_layers(_input_grid_info.get_power_layers()); @@ -85,39 +88,55 @@ void NetworkSynthesis::manualSetTemplates() auto horizontal_templates = _input_grid_info.get_horizontal_templates(); auto vertical_templates = _input_grid_info.get_vertical_templates(); - + auto layer_specific_templates = pnpConfig->get_layer_specific_templates(); + + auto* idb_layers = dmInst->get_idb_layout()->get_layers(); + + LOG_INFO << "Setting templates for " << layer_count << " power layers based on their actual directions"; + // distribute templates to each layer for (int layer_idx = 0; layer_idx < layer_count; ++layer_idx) { - int power_layer = power_layers[layer_idx]; - bool use_horizontal = (layer_idx % 2 == 1); + int power_layer_id = power_layers[layer_idx]; - LOG_INFO << "Layer " << power_layer << " Using " - << (use_horizontal ? "horizontal" : "vertical") << " templates"; + auto* routing_layer = idb_layers->find_routing_layer(power_layer_id); + auto* idb_layer_routing = dynamic_cast(routing_layer); + bool use_horizontal = idb_layer_routing->is_horizontal(); + std::string layer_name = routing_layer->get_name(); + + LOG_INFO << "Layer " << layer_name << " (ID: " << power_layer_id << ") Using " + << (use_horizontal ? "horizontal" : "vertical") << " direction from layer properties"; + for (int i = 0; i < ho_region_num; ++i) { for (int j = 0; j < ver_region_num; ++j) { - if (use_horizontal) { - // use horizontal template - _synthesized_network.set_single_template(layer_idx, i, j, horizontal_templates[1]); - } - else { - // use vertical template - _synthesized_network.set_single_template(layer_idx, i, j, vertical_templates[1]); - if (layer_idx == 2) { - SingleTemplate template_m7; - template_m7.set_direction(StripeDirection::kVertical); - template_m7.set_width(900.0); - template_m7.set_pg_offset(1600.0); - template_m7.set_space(19200.0); - template_m7.set_offset(8000.0); - _synthesized_network.set_single_template(layer_idx, i, j, template_m7); + SingleTemplate template_to_use; + + auto it = layer_specific_templates.find(layer_name); + if (it != layer_specific_templates.end()) { + template_to_use.set_direction(it->second.direction == "horizontal" ? + StripeDirection::kHorizontal : StripeDirection::kVertical); + template_to_use.set_width(it->second.width); + template_to_use.set_pg_offset(it->second.pg_offset); + template_to_use.set_space(it->second.space); + template_to_use.set_offset(it->second.offset); + + LOG_INFO << "Using layer-specific template for " << layer_name; + } else { + if (use_horizontal) { + template_to_use = horizontal_templates[0]; + } else { + template_to_use = vertical_templates[0]; } + + LOG_INFO << "Using default template for " << layer_name; } + + _synthesized_network.set_single_template(layer_idx, i, j, template_to_use); } } } - LOG_INFO << "Manual template setting completed with alternating horizontal and vertical templates."; + LOG_INFO << "Manual template setting completed based on actual layer directions from power_layers configuration."; } } // namespace ipnp diff --git a/src/operation/iPNP/source/module/synthesis/NetworkSynthesis.hh b/src/operation/iPNP/source/module/synthesis/NetworkSynthesis.hh index 152366659fd0dd034b048ed4dbbed8da4fee4f50..23d6a75c5b82364ffd23d259695265b3e6d93971 100644 --- a/src/operation/iPNP/source/module/synthesis/NetworkSynthesis.hh +++ b/src/operation/iPNP/source/module/synthesis/NetworkSynthesis.hh @@ -28,28 +28,7 @@ #include #include -#include "GridManager.hh" -#include "iPNPCommon.hh" - -namespace idb { -class IdbSpecialNet; -class IdbSpecialNetList; -class IdbSpecialWireList; -class IdbSpecialWire; -class IdbSpecialWireSegment; -class IdbLayer; -class IdbVia; -class IdbPin; -class IdbRect; -class IdbInstance; - -enum class SegmentType : int8_t; -enum class IdbWireShapeType : uint8_t; -enum class IdbOrient : uint8_t; - -template -class IdbCoordinate; -} // namespace idb +#include "PNPGridManager.hh" namespace ipnp { @@ -64,18 +43,18 @@ enum class SysnType class NetworkSynthesis { public: - NetworkSynthesis(SysnType sysn_type, GridManager grid_info); + NetworkSynthesis(SysnType sysn_type, PNPGridManager grid_info); ~NetworkSynthesis() = default; - GridManager get_network() { return _synthesized_network; } + PNPGridManager get_network() { return _synthesized_network; } void synthesizeNetwork(); -private: + private: void manualSetTemplates(); - GridManager _input_grid_info; - GridManager _synthesized_network; + PNPGridManager _input_grid_info; + PNPGridManager _synthesized_network; SysnType _network_sys_type; }; diff --git a/src/operation/iPNP/source/module/synthesis/PowerRouter.cpp b/src/operation/iPNP/source/module/synthesis/PowerRouter.cpp index a3cee4244d0cfa0ad490e07cb39d9865f53de5ac..b70a1b91e887739469ae1e4cefc687c07fe1cd85 100644 --- a/src/operation/iPNP/source/module/synthesis/PowerRouter.cpp +++ b/src/operation/iPNP/source/module/synthesis/PowerRouter.cpp @@ -29,42 +29,46 @@ #include #include +#include "IdbLayer.h" +#include "IdbSpecialNet.h" +#include "IdbSpecialWire.h" +#include "IdbVias.h" +#include "Log.hh" +#include "idm.h" +#include "PNPConfig.hh" + namespace ipnp { -void PowerRouter::addPowerStripesToCore(idb::IdbSpecialNet* power_net, GridManager pnp_network) +void PowerRouter::addPowerStripesToCore(idb::IdbSpecialNet* power_net, PNPGridManager pnp_network) { + auto idb_layers = dmInst->get_idb_layout()->get_layers(); std::string net_name; if (power_net->is_vdd()) { net_name = "VDD"; - } - else { + } else { net_name = "VSS"; } - idb::IdbSpecialWireList* wire_list = power_net->get_wire_list(); + auto* wire_list = power_net->get_wire_list(); auto grid_data = pnp_network.get_grid_data(); auto template_data = pnp_network.get_template_data(); auto power_layers = pnp_network.get_power_layers(); - for (int layer_idx = 0;layer_idx < pnp_network.get_layer_count();layer_idx++) { - + for (int layer_idx = 0; layer_idx < pnp_network.get_layer_count(); layer_idx++) { // Get the base coordinates of the core double x_base = pnp_network.get_core_llx(); double y_base = pnp_network.get_core_lly(); // Create a new routing layer - idb::IdbLayer* layer = new idb::IdbLayer(); - layer->set_name("M" + std::to_string(power_layers[layer_idx])); - layer->set_type(idb::IdbLayerType::kLayerRouting); + idb::IdbLayer* layer = idb_layers->find_routing_layer(power_layers[layer_idx]); // Begin: convert pnp_network to wire - idb::IdbSpecialWire* wire = new idb::IdbSpecialWire(); + auto* wire = new idb::IdbSpecialWire(); wire->set_wire_state(idb::IdbWiringStatement::kRouted); for (int i = 0; i < pnp_network.get_ho_region_num(); i++) { for (int j = 0; j < pnp_network.get_ver_region_num(); j++) { - SingleTemplate& single_template = template_data[layer_idx][i][j]; double width = single_template.get_width(); double space = single_template.get_space(); @@ -77,8 +81,7 @@ void PowerRouter::addPowerStripesToCore(idb::IdbSpecialNet* power_net, GridManag double current_segment_outermost; if (net_name == "VSS") { current_segment_outermost = offset + width; - } - else { // net_name == VDD + } else { // net_name == VDD current_segment_outermost = offset + width + pg_offset + width; } @@ -95,7 +98,7 @@ void PowerRouter::addPowerStripesToCore(idb::IdbSpecialNet* power_net, GridManag // Create a new segment idb::IdbSpecialWireSegment* segment = new idb::IdbSpecialWireSegment(); segment->set_layer(layer); - segment->set_route_width((int)width); + segment->set_route_width((int) width); segment->set_shape_type(idb::IdbWireShapeType::kStripe); // Set the segment coordinates @@ -103,8 +106,8 @@ void PowerRouter::addPowerStripesToCore(idb::IdbSpecialNet* power_net, GridManag double stripe_y1 = y_base + current_segment_outermost - 0.5 * width; double stripe_x2 = x_base + grid_data[layer_idx][i][j].get_width(); double stripe_y2 = stripe_y1; - segment->add_point((int)stripe_x1, (int)stripe_y1); - segment->add_point((int)stripe_x2, (int)stripe_y2); + segment->add_point((int) stripe_x1, (int) stripe_y1); + segment->add_point((int) stripe_x2, (int) stripe_y2); // Add the segment to the wire wire->add_segment(segment); @@ -113,8 +116,7 @@ void PowerRouter::addPowerStripesToCore(idb::IdbSpecialNet* power_net, GridManag current_segment_outermost += space; segment_count++; } - } - else { // direction is vertical + } else { // direction is vertical int max_segment_count = (grid_data[layer_idx][i][j].get_width() - offset) / space; if (grid_data[layer_idx][i][j].get_width() - offset - max_segment_count * space > 2 * width + pg_offset) { max_segment_count++; @@ -123,7 +125,7 @@ void PowerRouter::addPowerStripesToCore(idb::IdbSpecialNet* power_net, GridManag // Create a new segment idb::IdbSpecialWireSegment* segment = new idb::IdbSpecialWireSegment(); segment->set_layer(layer); - segment->set_route_width((int)width); + segment->set_route_width((int) width); segment->set_shape_type(idb::IdbWireShapeType::kStripe); // Set the segment coordinates @@ -131,8 +133,8 @@ void PowerRouter::addPowerStripesToCore(idb::IdbSpecialNet* power_net, GridManag double stripe_y1 = y_base; double stripe_x2 = stripe_x1; double stripe_y2 = y_base + grid_data[layer_idx][i][j].get_height(); - segment->add_point((int)stripe_x1, (int)stripe_y1); - segment->add_point((int)stripe_x2, (int)stripe_y2); + segment->add_point((int) stripe_x1, (int) stripe_y1); + segment->add_point((int) stripe_x2, (int) stripe_y2); // Add the segment to the wire wire->add_segment(segment); @@ -152,13 +154,14 @@ void PowerRouter::addPowerStripesToCore(idb::IdbSpecialNet* power_net, GridManag } } -void PowerRouter::addPowerStripesToDie(idb::IdbSpecialNet* power_net, GridManager pnp_network) +void PowerRouter::addPowerStripesToDie(idb::IdbSpecialNet* power_net, PNPGridManager pnp_network) { + auto idb_layers = dmInst->get_idb_layout()->get_layers(); + std::string net_name; if (power_net->is_vdd()) { net_name = "VDD"; - } - else { + } else { net_name = "VSS"; } @@ -168,24 +171,20 @@ void PowerRouter::addPowerStripesToDie(idb::IdbSpecialNet* power_net, GridManage auto template_data = pnp_network.get_template_data(); auto power_layers = pnp_network.get_power_layers(); - for (int layer_idx = 0;layer_idx < pnp_network.get_layer_count();layer_idx++) { - + for (int layer_idx = 0; layer_idx < pnp_network.get_layer_count(); layer_idx++) { // Get the base coordinates of the die double x_base = 0.0; double y_base = 0.0; // Create a new routing layer - idb::IdbLayer* layer = new idb::IdbLayer(); - layer->set_name("M" + std::to_string(power_layers[layer_idx])); - layer->set_type(idb::IdbLayerType::kLayerRouting); + idb::IdbLayer* layer = idb_layers->find_routing_layer(power_layers[layer_idx]); // Begin: convert pnp_network to wire - idb::IdbSpecialWire* wire = new idb::IdbSpecialWire(); + auto* wire = new idb::IdbSpecialWire(); wire->set_wire_state(idb::IdbWiringStatement::kRouted); for (int i = 0; i < pnp_network.get_ho_region_num(); i++) { for (int j = 0; j < pnp_network.get_ver_region_num(); j++) { - SingleTemplate& single_template = template_data[layer_idx][i][j]; double width = single_template.get_width(); double space = single_template.get_space(); @@ -198,8 +197,7 @@ void PowerRouter::addPowerStripesToDie(idb::IdbSpecialNet* power_net, GridManage double current_segment_outermost; if (net_name == "VSS") { current_segment_outermost = offset + width; - } - else { // net_name == VDD + } else { // net_name == VDD current_segment_outermost = offset + width + pg_offset + width; } @@ -216,7 +214,7 @@ void PowerRouter::addPowerStripesToDie(idb::IdbSpecialNet* power_net, GridManage // Create a new segment idb::IdbSpecialWireSegment* segment = new idb::IdbSpecialWireSegment(); segment->set_layer(layer); - segment->set_route_width((int)width); + segment->set_route_width((int) width); segment->set_shape_type(idb::IdbWireShapeType::kStripe); // Set the segment coordinates @@ -224,8 +222,8 @@ void PowerRouter::addPowerStripesToDie(idb::IdbSpecialNet* power_net, GridManage double stripe_y1 = y_base + current_segment_outermost - 0.5 * width; double stripe_x2 = x_base + grid_data[layer_idx][i][j].get_width(); double stripe_y2 = stripe_y1; - segment->add_point((int)stripe_x1, (int)stripe_y1); - segment->add_point((int)stripe_x2, (int)stripe_y2); + segment->add_point((int) stripe_x1, (int) stripe_y1); + segment->add_point((int) stripe_x2, (int) stripe_y2); // Add the segment to the wire wire->add_segment(segment); @@ -234,8 +232,7 @@ void PowerRouter::addPowerStripesToDie(idb::IdbSpecialNet* power_net, GridManage current_segment_outermost += space; segment_count++; } - } - else { // direction is vertical + } else { // direction is vertical int max_segment_count = (grid_data[layer_idx][i][j].get_width() - offset) / space; if (grid_data[layer_idx][i][j].get_width() - offset - max_segment_count * space > 2 * width + pg_offset) { max_segment_count++; @@ -244,7 +241,7 @@ void PowerRouter::addPowerStripesToDie(idb::IdbSpecialNet* power_net, GridManage // Create a new segment idb::IdbSpecialWireSegment* segment = new idb::IdbSpecialWireSegment(); segment->set_layer(layer); - segment->set_route_width((int)width); + segment->set_route_width((int) width); segment->set_shape_type(idb::IdbWireShapeType::kStripe); // Set the segment coordinates @@ -252,8 +249,8 @@ void PowerRouter::addPowerStripesToDie(idb::IdbSpecialNet* power_net, GridManage double stripe_y1 = y_base; double stripe_x2 = stripe_x1; double stripe_y2 = y_base + grid_data[layer_idx][i][j].get_height(); - segment->add_point((int)stripe_x1, (int)stripe_y1); - segment->add_point((int)stripe_x2, (int)stripe_y2); + segment->add_point((int) stripe_x1, (int) stripe_y1); + segment->add_point((int) stripe_x2, (int) stripe_y2); // Add the segment to the wire wire->add_segment(segment); @@ -272,29 +269,33 @@ void PowerRouter::addPowerStripesToDie(idb::IdbSpecialNet* power_net, GridManage wire_list->add_wire(wire, idb::IdbWiringStatement::kRouted); } - int wire_need_to_add = power_layers[0] - pnp_network.get_layer_count() - 2; + auto follow_pin_layers = pnpConfig->get_follow_pin_layers(); + int wire_need_to_add = power_layers[0] - pnp_network.get_layer_count() - static_cast(follow_pin_layers.size()); while (wire_need_to_add > 0) { - idb::IdbSpecialWire* wire = new idb::IdbSpecialWire(); + auto* wire = new idb::IdbSpecialWire(); wire->set_wire_state(idb::IdbWiringStatement::kRouted); wire_list->add_wire(wire, idb::IdbWiringStatement::kRouted); wire_need_to_add--; } } -void PowerRouter::addPowerFollowPin(idb::IdbDesign* idb_design, idb::IdbSpecialNet* power_net) +void PowerRouter::addPowerFollowPin(idb::IdbSpecialNet* power_net) { + auto idb_design = dmInst->get_idb_design(); auto rows = idb_design->get_layout()->get_rows(); auto wire_list = power_net->get_wire_list(); auto row_list = rows->get_row_list(); + auto idb_layers = dmInst->get_idb_layout()->get_layers(); - for (int layer_idx = 2; layer_idx > 0; layer_idx--) { - // Create a new routing layer - idb::IdbLayer* layer = new idb::IdbLayer(); - layer->set_name("M" + std::to_string(layer_idx)); - layer->set_type(idb::IdbLayerType::kLayerRouting); + auto follow_pin_layers = pnpConfig->get_follow_pin_layers(); + double follow_pin_width = pnpConfig->get_follow_pin_width(); + + for (const auto& layer_id : follow_pin_layers) { + + idb::IdbLayer* layer = idb_layers->find_routing_layer(layer_id); // Create a new wire - idb::IdbSpecialWire* wire = new idb::IdbSpecialWire(); + auto* wire = new idb::IdbSpecialWire(); wire->set_wire_state(idb::IdbWiringStatement::kRouted); int segment_idx; @@ -302,16 +303,15 @@ void PowerRouter::addPowerFollowPin(idb::IdbDesign* idb_design, idb::IdbSpecialN if (power_net->is_vdd()) { segment_idx = 0; - } - else { + } else { segment_idx = 1; } - while(segment_idx < row_num) { + while (segment_idx < row_num) { // Create a new follow pin segment idb::IdbSpecialWireSegment* segment = new idb::IdbSpecialWireSegment(); segment->set_layer(layer); - segment->set_route_width(300.0); + segment->set_route_width(follow_pin_width); segment->set_shape_type(idb::IdbWireShapeType::kFollowPin); // Set the segment coordinates @@ -319,8 +319,8 @@ void PowerRouter::addPowerFollowPin(idb::IdbDesign* idb_design, idb::IdbSpecialN double stripe_y1 = row_list[segment_idx]->get_original_coordinate()->get_y(); double stripe_x2 = stripe_x1 + idb_design->get_layout()->get_core()->get_bounding_box()->get_width(); double stripe_y2 = stripe_y1; - segment->add_point((int)stripe_x1, (int)stripe_y1); - segment->add_point((int)stripe_x2, (int)stripe_y2); + segment->add_point((int) stripe_x1, (int) stripe_y1); + segment->add_point((int) stripe_x2, (int) stripe_y2); // Add the segment to the wire wire->add_segment(segment); @@ -332,7 +332,7 @@ void PowerRouter::addPowerFollowPin(idb::IdbDesign* idb_design, idb::IdbSpecialN // Create a new follow pin segment idb::IdbSpecialWireSegment* segment = new idb::IdbSpecialWireSegment(); segment->set_layer(layer); - segment->set_route_width(300.0); + segment->set_route_width(follow_pin_width); segment->set_shape_type(idb::IdbWireShapeType::kFollowPin); // Set the segment coordinates @@ -340,8 +340,8 @@ void PowerRouter::addPowerFollowPin(idb::IdbDesign* idb_design, idb::IdbSpecialN double stripe_y1 = row_list[row_num - 1]->get_bounding_box()->get_high_y(); double stripe_x2 = stripe_x1 + idb_design->get_layout()->get_core()->get_bounding_box()->get_width(); double stripe_y2 = stripe_y1; - segment->add_point((int)stripe_x1, (int)stripe_y1); - segment->add_point((int)stripe_x2, (int)stripe_y2); + segment->add_point((int) stripe_x1, (int) stripe_y1); + segment->add_point((int) stripe_x2, (int) stripe_y2); // Add the segment to the wire wire->add_segment(segment); @@ -352,11 +352,29 @@ void PowerRouter::addPowerFollowPin(idb::IdbDesign* idb_design, idb::IdbSpecialN } } -void PowerRouter::addPowerPort(idb::IdbDesign* idb_design, GridManager pnp_network, std::string pin_name, std::string layer_name) +void PowerRouter::addPowerPort(PNPGridManager pnp_network, std::string pin_name, std::string layer_name) { + auto idb_design = dmInst->get_idb_design(); auto idb_layout = idb_design->get_layout(); idb::IdbLayer* layer = idb_layout->get_layers()->find_layer(layer_name); + // Find the corresponding template index for power_port_layer in power_layers + auto power_layers = pnpConfig->get_power_layers(); + int power_port_layer_id = pnpConfig->get_power_port_layer(); + + int template_layer_idx = -1; + for (size_t i = 0; i < power_layers.size(); i++) { + if (power_layers[i] == power_port_layer_id) { + template_layer_idx = static_cast(i); + break; + } + } + + if (template_layer_idx == -1) { + LOG_ERROR << "Power port layer ID " << power_port_layer_id << " not found in power_layers configuration!"; + return; + } + idb::IdbPin* io_pin = idb_design->get_io_pin_list()->find_pin(pin_name); if (io_pin == nullptr) { LOG_INFO << "Can not find " << pin_name << " in io_pin_list."; @@ -369,6 +387,9 @@ void PowerRouter::addPowerPort(idb::IdbDesign* idb_design, GridManager pnp_netwo io_pin->set_term(); idb_design->get_io_pin_list()->get_pin_list().emplace_back(io_pin); } + else { + io_pin->get_term()->get_port_list().clear(); + } // set term attribute idb::IdbTerm* term = io_pin->get_term(); @@ -376,8 +397,7 @@ void PowerRouter::addPowerPort(idb::IdbDesign* idb_design, GridManager pnp_netwo term->set_direction(idb::IdbConnectDirection::kInOut); if (pin_name == "VSS") { term->set_type(idb::IdbConnectType::kGround); - } - else { + } else { term->set_type(idb::IdbConnectType::kPower); } term->set_special(true); @@ -389,9 +409,9 @@ void PowerRouter::addPowerPort(idb::IdbDesign* idb_design, GridManager pnp_netwo double x_base = 0.0; double y_base = 0.0; - if (template_data[2][0][0].get_direction() == StripeDirection::kHorizontal) { + if (template_data[template_layer_idx][0][0].get_direction() == StripeDirection::kHorizontal) { for (int i = 0; i < pnp_network.get_ho_region_num(); i++) { - SingleTemplate& single_template = template_data[2][i][0]; + SingleTemplate& single_template = template_data[template_layer_idx][i][0]; double width = single_template.get_width(); double space = single_template.get_space(); double offset = single_template.get_offset(); @@ -400,15 +420,14 @@ void PowerRouter::addPowerPort(idb::IdbDesign* idb_design, GridManager pnp_netwo double current_outermost; if (pin_name == "VSS") { current_outermost = offset + width; - } - else { + } else { current_outermost = offset + width + pg_offset + width; } int port_count = 0; - int max_port_count = (grid_data[2][i][0].get_height() - offset) / space; - if (grid_data[2][i][0].get_height() - offset - max_port_count * space > 2 * width + pg_offset) { + int max_port_count = (grid_data[template_layer_idx][i][0].get_height() - offset) / space; + if (grid_data[template_layer_idx][i][0].get_height() - offset - max_port_count * space > 2 * width + pg_offset) { max_port_count++; } while (port_count < max_port_count) { @@ -442,12 +461,12 @@ void PowerRouter::addPowerPort(idb::IdbDesign* idb_design, GridManager pnp_netwo current_outermost += space; port_count++; } - y_base += grid_data[2][i][0].get_height(); + y_base += grid_data[template_layer_idx][i][0].get_height(); } - } // vertical + } // vertical else { - for (int j = 0;j < pnp_network.get_ver_region_num();j++) { - SingleTemplate& single_template = template_data[2][0][j]; + for (int j = 0; j < pnp_network.get_ver_region_num(); j++) { + SingleTemplate& single_template = template_data[template_layer_idx][0][j]; double width = single_template.get_width(); double space = single_template.get_space(); double offset = single_template.get_offset(); @@ -456,15 +475,14 @@ void PowerRouter::addPowerPort(idb::IdbDesign* idb_design, GridManager pnp_netwo double current_outermost; if (pin_name == "VSS") { current_outermost = offset + width; - } - else { + } else { current_outermost = offset + width + pg_offset + width; } int port_count = 0; - int max_port_count = (grid_data[2][0][j].get_width() - offset) / space; - if (grid_data[2][0][j].get_width() - offset - max_port_count * space > 2 * width + pg_offset) { + int max_port_count = (grid_data[template_layer_idx][0][j].get_width() - offset) / space; + if (grid_data[template_layer_idx][0][j].get_width() - offset - max_port_count * space > 2 * width + pg_offset) { max_port_count++; } while (port_count < max_port_count) { @@ -498,13 +516,15 @@ void PowerRouter::addPowerPort(idb::IdbDesign* idb_design, GridManager pnp_netwo current_outermost += space; port_count++; } - x_base += grid_data[2][0][j].get_width(); + x_base += grid_data[template_layer_idx][0][j].get_width(); } } } -void PowerRouter::addVSSNet(idb::IdbDesign* idb_design, GridManager pnp_network) +void PowerRouter::addVSSNet(PNPGridManager pnp_network) { + auto idb_design = dmInst->get_idb_design(); + idb::IdbSpecialNet* vss_net = idb_design->get_special_net_list()->find_net("VSS"); if (vss_net == nullptr) { @@ -522,15 +542,19 @@ void PowerRouter::addVSSNet(idb::IdbDesign* idb_design, GridManager pnp_network) addPowerStripesToDie(vss_net, pnp_network); LOG_INFO << "Add VSS Power Stripes success."; - addPowerFollowPin(idb_design, vss_net); + addPowerFollowPin(vss_net); LOG_INFO << "Add VSS Power Follow Pin success."; - addPowerPort(idb_design, pnp_network, "VSS", "M7"); + auto idb_layers = dmInst->get_idb_layout()->get_layers(); + auto* power_port_layer = idb_layers->find_routing_layer(pnpConfig->get_power_port_layer()); + addPowerPort(pnp_network, "VSS", power_port_layer->get_name()); LOG_INFO << "Add VSS Power Port success."; } -void PowerRouter::addVDDNet(idb::IdbDesign* idb_design, GridManager pnp_network) +void PowerRouter::addVDDNet(PNPGridManager pnp_network) { + auto idb_design = dmInst->get_idb_design(); + idb::IdbSpecialNet* vdd_net = idb_design->get_special_net_list()->find_net("VDD"); if (vdd_net == nullptr) { @@ -546,26 +570,23 @@ void PowerRouter::addVDDNet(idb::IdbDesign* idb_design, GridManager pnp_network) } addPowerStripesToDie(vdd_net, pnp_network); - LOG_INFO << "[iPNP info]: Add VDD Power Stripes success."; + LOG_INFO << "Add VDD Power Stripes success."; - addPowerFollowPin(idb_design, vdd_net); - LOG_INFO << "[iPNP info]: Add VDD Power Follow Pin success."; + addPowerFollowPin(vdd_net); + LOG_INFO << "Add VDD Power Follow Pin success."; - addPowerPort(idb_design, pnp_network, "VDD", "M7"); - LOG_INFO << "[iPNP info]: Add VDD Power Port success."; + auto idb_layers = dmInst->get_idb_layout()->get_layers(); + auto* power_port_layer = idb_layers->find_routing_layer(pnpConfig->get_power_port_layer()); + addPowerPort(pnp_network, "VDD", power_port_layer->get_name()); + LOG_INFO << "Add VDD Power Port success."; } -void PowerRouter::addPowerNets(idb::IdbDesign* idb_design, GridManager pnp_network) +void PowerRouter::addPowerNets(PNPGridManager pnp_network) { - if (!idb_design) { - LOG_INFO << "Invalid IDB design object." << std::endl; - return; - } - - addVSSNet(idb_design, pnp_network); + addVSSNet(pnp_network); LOG_INFO << "Add VSS Power Nets success."; - addVDDNet(idb_design, pnp_network); + addVDDNet(pnp_network); LOG_INFO << "Add VDD Power Nets success."; } diff --git a/src/operation/iPNP/source/module/synthesis/PowerRouter.hh b/src/operation/iPNP/source/module/synthesis/PowerRouter.hh index 1bceecc783a1899cfcfcf3e4c25c09a2f83af5fb..44c41f5b7b1660b9df445e8d41f40ad589a24506 100644 --- a/src/operation/iPNP/source/module/synthesis/PowerRouter.hh +++ b/src/operation/iPNP/source/module/synthesis/PowerRouter.hh @@ -29,49 +29,30 @@ #include #include -#include "GridManager.hh" -#include "iPNPCommon.hh" +#include "PNPGridManager.hh" namespace idb { -class IdbDesign; class IdbSpecialNet; -class IdbSpecialNetList; -class IdbSpecialWireList; -class IdbSpecialWire; -class IdbSpecialWireSegment; -class IdbLayer; -class IdbVia; -class IdbPin; -class IdbRect; -class IdbInstance; - -enum class SegmentType : int8_t; -enum class IdbWireShapeType : uint8_t; -enum class IdbOrient : uint8_t; - -template -class IdbCoordinate; -} // namespace idb +} namespace ipnp { class PowerRouter { -public: + public: PowerRouter() = default; ~PowerRouter() = default; - void addPowerNets(idb::IdbDesign* idb_design, GridManager pnp_network); + void addPowerNets(PNPGridManager pnp_network); -private: + private: + void addPowerStripesToCore(idb::IdbSpecialNet* power_net, PNPGridManager pnp_network); + void addPowerStripesToDie(idb::IdbSpecialNet* power_net, PNPGridManager pnp_network); + void addPowerFollowPin(idb::IdbSpecialNet* power_net); + void addPowerPort(PNPGridManager pnp_network, std::string pin_name, std::string layer_name); - void addPowerStripesToCore(idb::IdbSpecialNet* power_net, GridManager pnp_network); - void addPowerStripesToDie(idb::IdbSpecialNet* power_net, GridManager pnp_network); - void addPowerFollowPin(idb::IdbDesign* idb_design, idb::IdbSpecialNet* power_net); - void addPowerPort(idb::IdbDesign* idb_design, GridManager pnp_network, std::string pin_name, std::string layer_name); - - void addVSSNet(idb::IdbDesign* idb_design, GridManager pnp_network); - void addVDDNet(idb::IdbDesign* idb_design, GridManager pnp_network); + void addVSSNet(PNPGridManager pnp_network); + void addVDDNet(PNPGridManager pnp_network); }; } // namespace ipnp \ No newline at end of file diff --git a/src/operation/iPNP/source/module/synthesis/PowerVia.cpp b/src/operation/iPNP/source/module/synthesis/PowerVia.cpp index 31f6c79dbb998a5df5fadea497a3dac6ede59d1d..7a0374bd2fb7792d2dc1186f6b66ea1d881c7f2b 100644 --- a/src/operation/iPNP/source/module/synthesis/PowerVia.cpp +++ b/src/operation/iPNP/source/module/synthesis/PowerVia.cpp @@ -17,13 +17,14 @@ /** * @file PowerVia.cpp * @author Jianrong Su - * @brief + * @brief * @version 1.0 * @date 2025-06-23 */ #include "PowerVia.hh" +#include #include #include #include @@ -32,622 +33,627 @@ #include #include +#include "IdbLayer.h" +#include "IdbSpecialNet.h" +#include "IdbSpecialWire.h" +#include "IdbViaMaster.h" +#include "IdbVias.h" +#include "Log.hh" +#include "idm.h" + namespace ipnp { - idb::IdbDesign* PowerVia::connectAllPowerLayers(GridManager& pnp_network, idb::IdbDesign* idb_design) - { - if (!idb_design) { - LOG_INFO << "Error : Invalid IDB design object"; - return nullptr; - } +void PowerVia::connectAllPowerLayers(PNPGridManager& pnp_network) +{ + connectNetworkLayers(pnp_network, PowerType::kVDD); - idb_design = connectNetworkLayers(pnp_network, PowerType::kVDD, idb_design); + connectNetworkLayers(pnp_network, PowerType::kVSS); - idb_design = connectNetworkLayers(pnp_network, PowerType::kVSS, idb_design); + LOG_INFO << "Success : Connected all power layers"; +} - LOG_INFO << "Success : Connected all power layers"; - return idb_design; - } +void PowerVia::connectM2M1Layer() +{ + connect_M2_M1("VDD"); + connect_M2_M1("VSS"); - idb::IdbDesign* PowerVia::connectM2M1Layer(idb::IdbDesign* idb_design) - { - idb_design = connect_M2_M1("VDD", idb_design); - idb_design = connect_M2_M1("VSS", idb_design); + LOG_INFO << "Success : Connected M2 and M1 layers"; +} - LOG_INFO << "Success : Connected M2 and M1 layers"; - return idb_design; - } +void PowerVia::connectNetworkLayers(PNPGridManager& pnp_network, PowerType net_type) +{ + auto idb_layers = dmInst->get_idb_layout()->get_layers(); + std::string net_name = (net_type == PowerType::kVDD) ? "VDD" : "VSS"; - idb::IdbDesign* PowerVia::connectNetworkLayers(GridManager& pnp_network, PowerType net_type, idb::IdbDesign* idb_design) - { - std::string net_name = (net_type == PowerType::kVDD) ? "VDD" : "VSS"; + auto power_layers = pnp_network.get_power_layers(); - auto power_layers = pnp_network.get_power_layers(); - int layer_count = pnp_network.get_layer_count(); + // Connect power layers + for (size_t i = 0; i < power_layers.size() - 1; i++) { - // Connect power layers - for (int i = 0; i < layer_count - 1; i++) { - std::string top_layer = "M" + std::to_string(power_layers[i]); - std::string bottom_layer = "M" + std::to_string(power_layers[i + 1]); - idb_design = connectLayers(net_name, top_layer, bottom_layer, idb_design); - } + auto* top_layer = idb_layers->find_routing_layer(power_layers[i]); + auto* bottom_layer = idb_layers->find_routing_layer(power_layers[i + 1]); + + if (top_layer && bottom_layer) { + std::string top_layer_name = top_layer->get_name(); + std::string bottom_layer_name = bottom_layer->get_name(); - // Connect power layer to M2 and M1 layer rows - std::string bottom_power_layer = "M" + std::to_string(power_layers[layer_count - 1]); - idb_design = connect_Layer_Row(net_name, bottom_power_layer, "M2", idb_design); - - LOG_INFO << "Success : Connected all layers for " << net_name; - return idb_design; + LOG_INFO << "Connecting layers: " << top_layer_name << " -> " << bottom_layer_name; + connectLayers(net_name, top_layer_name, bottom_layer_name); + } + else { + LOG_ERROR << "Cannot find routing layers for IDs: " << power_layers[i] << ", " << power_layers[i + 1]; + } } - int32_t PowerVia::transUnitDB(double value, idb::IdbDesign* idb_design) - { - if (!idb_design) return -1; - auto idb_layout = idb_design->get_layout(); - return idb_layout != nullptr ? idb_layout->transUnitDB(value) : -1; + // Connect power layer to rows + auto* bottom_power_layer = idb_layers->find_routing_layer(power_layers.back()); + auto follow_pin_layers = pnpConfig->get_follow_pin_layers(); + + int bottom_routing_id = *std::min_element(follow_pin_layers.begin(), follow_pin_layers.end()); + auto* bottom_routing_layer = idb_layers->find_routing_layer(bottom_routing_id); + + if (bottom_power_layer && bottom_routing_layer) { + std::string bottom_power_name = bottom_power_layer->get_name(); + std::string bottom_routing_name = bottom_routing_layer->get_name(); + + LOG_INFO << "Connecting power layer to bottom routing layer: " + << bottom_power_name << " -> " << bottom_routing_name; + connect_Layer_Row(net_name, bottom_power_name, bottom_routing_name); + } + else { + LOG_WARNING << "Cannot find bottom power layer or bottom routing layer"; } - idb::IdbVia* PowerVia::findVia(idb::IdbLayerCut* layer_cut, int32_t width_design, int32_t height_design, idb::IdbDesign* idb_design) - { - if (!idb_design) return nullptr; - auto via_list = idb_design->get_via_list(); + LOG_INFO << "Success : Connected all layers for " << net_name; +} - // Via name format: cut_layer_name_widthxheight - std::string via_name = layer_cut->get_name() + "_" + std::to_string(width_design) + "x" + std::to_string(height_design); +int32_t PowerVia::transUnitDB(double value) +{ + auto idb_layout = dmInst->get_idb_layout(); + return idb_layout != nullptr ? idb_layout->transUnitDB(value) : -1; +} - // Search for existing via - idb::IdbVia* via_find = via_list->find_via(via_name); +idb::IdbVia* PowerVia::findVia(idb::IdbLayerCut* layer_cut, int32_t width_design, int32_t height_design) +{ + auto idb_design = dmInst->get_idb_design(); - // If not found, create a new via - if (via_find == nullptr) { - via_find = createVia(layer_cut, width_design, height_design, via_name, idb_design); - } + auto via_list = idb_design->get_via_list(); + + // Via name format: cut_layer_name_widthxheight + std::string via_name = layer_cut->get_name() + "_" + std::to_string(width_design) + "x" + std::to_string(height_design); - return via_find; + // Search for existing via + idb::IdbVia* via_find = via_list->find_via(via_name); + + // If not found, create a new via + if (via_find == nullptr) { + via_find = createVia(layer_cut, width_design, height_design, via_name); } - idb::IdbVia* PowerVia::createVia(idb::IdbLayerCut* layer_cut, int32_t width_design, int32_t height_design, std::string via_name, idb::IdbDesign* idb_design) - { - if (!idb_design) return nullptr; - auto via_list = idb_design->get_via_list(); + return via_find; +} - // Ensure via name is correctly formatted - via_name = layer_cut->get_name() + "_" + std::to_string(width_design) + "x" + std::to_string(height_design); +idb::IdbVia* PowerVia::createVia(idb::IdbLayerCut* layer_cut, int32_t width_design, int32_t height_design, std::string via_name) +{ + auto idb_design = dmInst->get_idb_design(); - // Create via - idb::IdbVia* via = via_list->createVia(via_name, layer_cut, width_design, height_design); + auto via_list = idb_design->get_via_list(); - // Debug information - LOG_INFO << "Created via: " << via_name << ", via_list size: " << via_list->get_via_list().size(); + // Ensure via name is correctly formatted + via_name = layer_cut->get_name() + "_" + std::to_string(width_design) + "x" + std::to_string(height_design); - return via; - } + // Create via + idb::IdbVia* via = via_list->createVia(via_name, layer_cut, width_design, height_design); - idb::IdbSpecialWireSegment* PowerVia::createSpecialWireVia(idb::IdbLayer* layer, int32_t route_width, - idb::IdbWireShapeType wire_shape_type, - idb::IdbCoordinate* coord, - idb::IdbVia* via) - { - // Create special wire segment - idb::IdbSpecialWireSegment* segment_via = new idb::IdbSpecialWireSegment(); + // Debug information + LOG_INFO << "Created via: " << via_name << ", via_list size: " << via_list->get_via_list().size(); - // Set as via type - segment_via->set_is_via(true); + return via; +} - // Add coordinate point - segment_via->add_point(coord->get_x(), coord->get_y()); +idb::IdbSpecialWireSegment* PowerVia::createSpecialWireVia(idb::IdbLayer* layer, int32_t route_width, idb::IdbWireShapeType wire_shape_type, + idb::IdbCoordinate* coord, idb::IdbVia* via) +{ + // Create special wire segment + idb::IdbSpecialWireSegment* segment_via = new idb::IdbSpecialWireSegment(); - // Set layer information - segment_via->set_layer(layer); + // Set as via type + segment_via->set_is_via(true); - // Set shape type - segment_via->set_shape_type(idb::IdbWireShapeType::kStripe); + // Add coordinate point + segment_via->add_point(coord->get_x(), coord->get_y()); - // Mark as new layer - segment_via->set_layer_as_new(); + // Set layer information + segment_via->set_layer(layer); - // Set route width - segment_via->set_route_width(0); + // Set shape type + segment_via->set_shape_type(idb::IdbWireShapeType::kStripe); - // Copy via and set coordinates - idb::IdbVia* via_new = segment_via->copy_via(via); - if (via_new != nullptr) { - via_new->set_coordinate(coord); - } + // Mark as new layer + segment_via->set_layer_as_new(); - // Set bounding box - segment_via->set_bounding_box(); + // Set route width + segment_via->set_route_width(0); - return segment_via; + // Copy via and set coordinates + idb::IdbVia* via_new = segment_via->copy_via(via); + if (via_new != nullptr) { + via_new->set_coordinate(coord); } - bool PowerVia::getIntersectCoordinate(idb::IdbSpecialWireSegment* segment_top, - idb::IdbSpecialWireSegment* segment_bottom, - idb::IdbRect& intersection_rect) - { - // Get segment bounding boxes - idb::IdbRect* top_bbox = segment_top->get_bounding_box(); - idb::IdbRect* bottom_bbox = segment_bottom->get_bounding_box(); + // Set bounding box + segment_via->set_bounding_box(); - // Check if there is intersection - if (!top_bbox->isIntersection(bottom_bbox)) { - return false; - } + return segment_via; +} - // Calculate intersection area - int32_t ll_x = std::max(top_bbox->get_low_x(), bottom_bbox->get_low_x()); - int32_t ll_y = std::max(top_bbox->get_low_y(), bottom_bbox->get_low_y()); - int32_t ur_x = std::min(top_bbox->get_high_x(), bottom_bbox->get_high_x()); - int32_t ur_y = std::min(top_bbox->get_high_y(), bottom_bbox->get_high_y()); +bool PowerVia::getIntersectCoordinate(idb::IdbSpecialWireSegment* segment_top, idb::IdbSpecialWireSegment* segment_bottom, + idb::IdbRect& intersection_rect) +{ + // Get segment bounding boxes + idb::IdbRect* top_bbox = segment_top->get_bounding_box(); + idb::IdbRect* bottom_bbox = segment_bottom->get_bounding_box(); - // Set intersection rectangle - intersection_rect.set_rect(ll_x, ll_y, ur_x, ur_y); + // Check if there is intersection + if (!top_bbox->isIntersection(bottom_bbox)) { + return false; + } - return true; + // Calculate intersection area + int32_t ll_x = std::max(top_bbox->get_low_x(), bottom_bbox->get_low_x()); + int32_t ll_y = std::max(top_bbox->get_low_y(), bottom_bbox->get_low_y()); + int32_t ur_x = std::min(top_bbox->get_high_x(), bottom_bbox->get_high_x()); + int32_t ur_y = std::min(top_bbox->get_high_y(), bottom_bbox->get_high_y()); + + // Set intersection rectangle + intersection_rect.set_rect(ll_x, ll_y, ur_x, ur_y); + + return true; +} + +bool PowerVia::addSingleVia(std::string net_name, std::string top_layer, std::string bottom_layer, double x, double y, int32_t width, + int32_t height) +{ + auto idb_design = dmInst->get_idb_design(); + auto idb_layout = dmInst->get_idb_layout(); + auto idb_layer_list = idb_layout->get_layers(); + auto idb_pdn_list = idb_design->get_special_net_list(); + + // Find network + idb::IdbSpecialNet* net = idb_pdn_list->find_net(net_name); + if (net == nullptr) { + LOG_INFO << "Error: Cannot find net " << net_name; + return false; } - bool PowerVia::addSingleVia(std::string net_name, - std::string top_layer, - std::string bottom_layer, - double x, double y, - int32_t width, int32_t height, - idb::IdbDesign* idb_design) - { - if (!idb_design) return false; + // Get wire + idb::IdbSpecialWire* wire = nullptr; + if (net->get_wire_list()->get_num() > 0) { + wire = net->get_wire_list()->find_wire(0); + } else { + wire = net->get_wire_list()->add_wire(nullptr); + } - auto idb_layout = idb_design->get_layout(); - auto idb_layer_list = idb_layout->get_layers(); - auto idb_pdn_list = idb_design->get_special_net_list(); + if (wire == nullptr) { + LOG_INFO << "Error: Cannot get wire for net " << net_name; + return false; + } - // Find network - idb::IdbSpecialNet* net = idb_pdn_list->find_net(net_name); - if (net == nullptr) { - LOG_INFO << "Error: Cannot find net " << net_name; - return false; - } + // Find all cut layers + std::vector cut_layer_list = idb_layer_list->find_cut_layer_list(top_layer, bottom_layer); - // Get wire - idb::IdbSpecialWire* wire = nullptr; - if (net->get_wire_list()->get_num() > 0) { - wire = net->get_wire_list()->find_wire(0); - } - else { - wire = net->get_wire_list()->add_wire(nullptr); - } + if (cut_layer_list.empty()) { + LOG_INFO << "Error: No cut layers found between " << top_layer << " and " << bottom_layer; + return false; + } - if (wire == nullptr) { - LOG_INFO << "Error: Cannot get wire for net " << net_name; - return false; - } + // Convert coordinates to database units + int32_t dbu_x = transUnitDB(x); + int32_t dbu_y = transUnitDB(y); - // Find all cut layers - std::vector cut_layer_list = - idb_layer_list->find_cut_layer_list(top_layer, bottom_layer); + // Add via for each cut layer + for (auto layer_cut : cut_layer_list) { + if (!layer_cut->is_cut()) + continue; - if (cut_layer_list.empty()) { - LOG_INFO << "Error: No cut layers found between " << top_layer << " and " << bottom_layer; - return false; + // Find or create via + idb::IdbVia* via = findVia(layer_cut, width, height); + if (via == nullptr) { + LOG_INFO << "Error: Failed to create via for " << layer_cut->get_name(); + continue; } - // Convert coordinates to database units - int32_t dbu_x = transUnitDB(x, idb_design); - int32_t dbu_y = transUnitDB(y, idb_design); + // Get via top layer + idb::IdbLayer* via_top_layer = via->get_top_layer_shape().get_layer(); - // Add via for each cut layer - for (auto layer_cut : cut_layer_list) { - if (!layer_cut->is_cut()) continue; + // Create coordinate + idb::IdbCoordinate* coord = new idb::IdbCoordinate(dbu_x, dbu_y); - // Find or create via - idb::IdbVia* via = findVia(layer_cut, width, height, idb_design); - if (via == nullptr) { - LOG_INFO << "Error: Failed to create via for " << layer_cut->get_name(); - continue; - } + // Create via segment + idb::IdbSpecialWireSegment* segment_via = createSpecialWireVia(via_top_layer, 0, idb::IdbWireShapeType::kStripe, coord, via); + + // Add to wire + wire->add_segment(segment_via); + } - // Get via top layer - idb::IdbLayer* via_top_layer = via->get_top_layer_shape().get_layer(); + return true; +} - // Create coordinate - idb::IdbCoordinate* coord = new idb::IdbCoordinate(dbu_x, dbu_y); +void PowerVia::connectLayers(std::string net_name, std::string top_layer_name, std::string bottom_layer_name) +{ + auto idb_design = dmInst->get_idb_design(); - // Create via segment - idb::IdbSpecialWireSegment* segment_via = createSpecialWireVia( - via_top_layer, 0, idb::IdbWireShapeType::kStripe, coord, via); + auto idb_layout = dmInst->get_idb_layout(); + auto idb_layer_list = idb_layout->get_layers(); + auto idb_pdn_list = idb_design->get_special_net_list(); - // Add to wire - wire->add_segment(segment_via); - } + // Get layer information + idb::IdbLayerRouting* layer_bottom = dynamic_cast(idb_layer_list->find_layer(bottom_layer_name)); + idb::IdbLayerRouting* layer_top = dynamic_cast(idb_layer_list->find_layer(top_layer_name)); - return true; + // Ensure layers exist and are different + if (layer_bottom == nullptr || layer_top == nullptr || layer_bottom == layer_top) { + LOG_INFO << "Error : layers not exist or same layer."; + return; } - idb::IdbDesign* PowerVia::connectLayers(std::string net_name, std::string top_layer_name, std::string bottom_layer_name, idb::IdbDesign* idb_design) - { - if (!idb_design) { - LOG_INFO << "Error : Invalid IDB design object"; - return nullptr; - } + // Ensure bottom layer is below top layer + if (layer_top->get_order() < layer_bottom->get_order()) { + std::swap(layer_top, layer_bottom); + } - auto idb_layout = idb_design->get_layout(); - auto idb_layer_list = idb_layout->get_layers(); - auto idb_pdn_list = idb_design->get_special_net_list(); + // Don't support two layers with the same direction + if ((layer_top->is_horizontal() && layer_bottom->is_horizontal()) || (layer_top->is_vertical() && layer_bottom->is_vertical())) { + LOG_INFO << "Error : layers have the same direction."; + return; + } - // Get layer information - idb::IdbLayerRouting* layer_bottom = dynamic_cast( - idb_layer_list->find_layer(bottom_layer_name)); - idb::IdbLayerRouting* layer_top = dynamic_cast( - idb_layer_list->find_layer(top_layer_name)); + // Get network + idb::IdbSpecialNet* net = idb_pdn_list->find_net(net_name); + if (net == nullptr) { + LOG_INFO << "Error : can't find the net " << net_name; + return; + } - // Ensure layers exist and are different - if (layer_bottom == nullptr || layer_top == nullptr || layer_bottom == layer_top) { - LOG_INFO << "Error : layers not exist or same layer."; - return nullptr; - } + // Get network wire list + idb::IdbSpecialWireList* wire_list = net->get_wire_list(); + if (wire_list == nullptr) { + LOG_INFO << "Error : not wire in Special net " << net_name; + return; + } - // Ensure bottom layer is below top layer - if (layer_top->get_order() < layer_bottom->get_order()) { - std::swap(layer_top, layer_bottom); - } + std::vector segment_list_top; + std::vector segment_list_bottom; + idb::IdbSpecialWire* wire_top = nullptr; + + // Collect top and bottom layer segments + for (idb::IdbSpecialWire* wire : wire_list->get_wire_list()) { + for (idb::IdbSpecialWireSegment* segment : wire->get_segment_list()) { + if (segment->is_tripe() || segment->is_follow_pin()) { + if (segment->get_layer()->compareLayer(layer_top)) { + segment->set_bounding_box(); + segment_list_top.emplace_back(segment); + wire_top = wire; + } - // Don't support two layers with the same direction - if ((layer_top->is_horizontal() && layer_bottom->is_horizontal()) || - (layer_top->is_vertical() && layer_bottom->is_vertical())) { - LOG_INFO << "Error : layers have the same direction."; - return nullptr; + if (segment->get_layer()->compareLayer(layer_bottom)) { + segment->set_bounding_box(); + segment_list_bottom.emplace_back(segment); + } + } } + } - // Get network - idb::IdbSpecialNet* net = idb_pdn_list->find_net(net_name); - if (net == nullptr) { - LOG_INFO << "Error : can't find the net " << net_name; - return nullptr; - } + // For each top layer segment + for (idb::IdbSpecialWireSegment* segment_top : segment_list_top) { + // For each bottom layer segment + for (idb::IdbSpecialWireSegment* segment_bottom : segment_list_bottom) { + // Calculate intersection area + idb::IdbRect intersection_rect; + if (getIntersectCoordinate(segment_top, segment_bottom, intersection_rect)) { + + // Add via for each intermediate layer + for (int32_t layer_order = layer_bottom->get_order(); layer_order <= (layer_top->get_order() - 2);) { + // Get cut layer + idb::IdbLayerCut* layer_cut_find = dynamic_cast(idb_layer_list->find_layer_by_order(layer_order + 1)); + + if (layer_cut_find == nullptr) { + LOG_INFO << "Error : layer input illegal."; + return; + } - // Get network wire list - idb::IdbSpecialWireList* wire_list = net->get_wire_list(); - if (wire_list == nullptr) { - LOG_INFO << "Error : not wire in Special net " << net_name; - return nullptr; - } + // Find or create via + idb::IdbVia* via_find = findVia(layer_cut_find, intersection_rect.get_width(), intersection_rect.get_height()); - std::vector segment_list_top; - std::vector segment_list_bottom; - idb::IdbSpecialWire* wire_top = nullptr; - - // Collect top and bottom layer segments - for (idb::IdbSpecialWire* wire : wire_list->get_wire_list()) { - for (idb::IdbSpecialWireSegment* segment : wire->get_segment_list()) { - if (segment->is_tripe() || segment->is_follow_pin()) { - if (segment->get_layer()->compareLayer(layer_top)) { - segment->set_bounding_box(); - segment_list_top.emplace_back(segment); - wire_top = wire; + if (via_find == nullptr) { + LOG_INFO << "Error : can not find VIA matchs."; + continue; } - if (segment->get_layer()->compareLayer(layer_bottom)) { - segment->set_bounding_box(); - segment_list_bottom.emplace_back(segment); - } + // Get via top layer + idb::IdbLayer* layer_top_via = via_find->get_top_layer_shape().get_layer(); + + // Create coordinate + idb::IdbCoordinate middle = intersection_rect.get_middle_point(); + idb::IdbCoordinate* middle_ptr = new idb::IdbCoordinate(middle.get_x(), middle.get_y()); + + // Create via segment + idb::IdbSpecialWireSegment* segment_via + = createSpecialWireVia(layer_top_via, 0, idb::IdbWireShapeType::kStripe, middle_ptr, via_find); + + // Add to wire + wire_top->add_segment(segment_via); + + // Move to next cut layer + layer_order += 2; } } } - - // For each top layer segment - for (idb::IdbSpecialWireSegment* segment_top : segment_list_top) { - // For each bottom layer segment - for (idb::IdbSpecialWireSegment* segment_bottom : segment_list_bottom) { - // Calculate intersection area - idb::IdbRect intersection_rect; - if (getIntersectCoordinate(segment_top, segment_bottom, intersection_rect)) { - // Debug information - // LOG_INFO << "Found intersection at (" << intersection_rect.get_middle_point().get_x() - // << ", " << intersection_rect.get_middle_point().get_y() - // << ") with size " << intersection_rect.get_width() << "x" << intersection_rect.get_height(); - - // Add via for each intermediate layer - for (int32_t layer_order = layer_bottom->get_order(); - layer_order <= (layer_top->get_order() - 2);) - { - // Get cut layer - idb::IdbLayerCut* layer_cut_find = dynamic_cast( - idb_layer_list->find_layer_by_order(layer_order + 1)); - - if (layer_cut_find == nullptr) { - LOG_INFO << "Error : layer input illegal."; - return nullptr; - } - - // Find or create via - idb::IdbVia* via_find = findVia(layer_cut_find, - intersection_rect.get_width(), - intersection_rect.get_height(), - idb_design); - - if (via_find == nullptr) { - LOG_INFO << "Error : can not find VIA matchs."; - continue; - } - - // Get via top layer - idb::IdbLayer* layer_top_via = via_find->get_top_layer_shape().get_layer(); - - // Create coordinate - idb::IdbCoordinate middle = intersection_rect.get_middle_point(); - idb::IdbCoordinate* middle_ptr = new idb::IdbCoordinate(middle.get_x(), middle.get_y()); - - // Create via segment - idb::IdbSpecialWireSegment* segment_via = createSpecialWireVia( - layer_top_via, 0, idb::IdbWireShapeType::kStripe, middle_ptr, via_find); - - // Add to wire - wire_top->add_segment(segment_via); - - // Move to next cut layer - layer_order += 2; - } + } + + LOG_INFO << "Success : connectLayers " << top_layer_name << " & " << bottom_layer_name; +} + +void PowerVia::connect_Layer_Row(std::string net_name, std::string top_layer_name, std::string bottom_layer_name) +{ + auto idb_layout = dmInst->get_idb_layout(); + auto idb_design = dmInst->get_idb_design(); + auto idb_layer_list = idb_layout->get_layers(); + auto idb_pdn_list = idb_design->get_special_net_list(); + + // Get layer information + idb::IdbLayerRouting* layer_bottom = dynamic_cast(idb_layer_list->find_layer(bottom_layer_name)); + idb::IdbLayerRouting* layer_top = dynamic_cast(idb_layer_list->find_layer(top_layer_name)); + + // Ensure layers exist and are different + if (layer_bottom == nullptr || layer_top == nullptr || layer_bottom == layer_top) { + LOG_INFO << "Error : layers not exist or same layer."; + return; + } + + // Ensure bottom layer is below top layer + if (layer_top->get_order() < layer_bottom->get_order()) { + std::swap(layer_top, layer_bottom); + std::swap(top_layer_name, bottom_layer_name); + } + + // Don't support two layers with the same direction + if ((layer_top->is_horizontal() && layer_bottom->is_horizontal()) || + (layer_top->is_vertical() && layer_bottom->is_vertical())) { + LOG_INFO << "Error : layers have the same direction."; + return; + } + + // Get network + idb::IdbSpecialNet* net = idb_pdn_list->find_net(net_name); + if (net == nullptr) { + LOG_INFO << "Error : can't find the net " << net_name; + return; + } + + // Get network wire list + idb::IdbSpecialWireList* wire_list = net->get_wire_list(); + if (wire_list == nullptr) { + LOG_INFO << "Error : not wire in Special net " << net_name; + return; + } + + std::vector segment_list_top; + std::vector segment_list_bottom; + + // Collect top and bottom layer segments + for (idb::IdbSpecialWire* wire : wire_list->get_wire_list()) { + for (idb::IdbSpecialWireSegment* segment : wire->get_segment_list()) { + if (segment->is_tripe() || segment->is_follow_pin()) { + if (segment->get_layer()->compareLayer(layer_top)) { + segment->set_bounding_box(); + segment_list_top.emplace_back(segment); + } + if (segment->get_layer()->compareLayer(layer_bottom)) { + segment->set_bounding_box(); + segment_list_bottom.emplace_back(segment); } } } - - LOG_INFO << "Success : connectLayers " << top_layer_name << " & " << bottom_layer_name; - return idb_design; } + // Get power_layers configuration to determine wire index + auto power_layers = pnpConfig->get_power_layers(); + auto idb_layers = dmInst->get_idb_layout()->get_layers(); - idb::IdbDesign* PowerVia::connect_Layer_Row(std::string net_name, std::string top_layer_name, std::string bottom_layer_name, idb::IdbDesign* idb_design) - { - auto idb_layout = idb_design->get_layout(); - auto idb_layer_list = idb_layout->get_layers(); - auto idb_pdn_list = idb_design->get_special_net_list(); - - // Get layer information - idb::IdbLayerRouting* layer_M2 = dynamic_cast( - idb_layer_list->find_layer(bottom_layer_name)); - idb::IdbLayerRouting* layer_top = dynamic_cast( - idb_layer_list->find_layer(top_layer_name)); - idb::IdbLayerRouting* layer_M9 = dynamic_cast( - idb_layer_list->find_layer("M9")); - - // Ensure layers exist and are different - if (layer_M2 == nullptr || layer_top == nullptr || layer_M2 == layer_top) { - LOG_INFO << "Error : layers not exist or same layer."; - return nullptr; + // Find the index of top_layer in power_layers + int top_layer_index = -1; + for (size_t i = 0; i < power_layers.size(); i++) { + auto* power_layer = idb_layers->find_routing_layer(power_layers[i]); + if (power_layer && power_layer->get_name() == top_layer_name) { + top_layer_index = static_cast(i); + break; } + } + + if (top_layer_index == -1) { + LOG_INFO << "Error : top layer " << top_layer_name << " not found in power_layers configuration."; + return; + } - // Ensure bottom layer is below top layer - if (layer_top->get_order() < layer_M2->get_order()) { - std::swap(layer_top, layer_M2); - } + // For each top layer segment + for (idb::IdbSpecialWireSegment* segment_top : segment_list_top) { + // For each bottom layer segment + for (idb::IdbSpecialWireSegment* segment_bottom : segment_list_bottom) { + // Calculate intersection area + idb::IdbRect intersection_rect; + if (getIntersectCoordinate(segment_top, segment_bottom, intersection_rect)) { + int32_t layer_order_bottom = layer_bottom->get_order(); + int32_t layer_order_top = layer_top->get_order(); + + // Create coordinate + idb::IdbCoordinate middle = intersection_rect.get_middle_point(); + idb::IdbCoordinate* middle_ptr = new idb::IdbCoordinate(middle.get_x(), middle.get_y()); + + int current_wire_index = top_layer_index; + + // Process each cut layer between top and bottom + for (int layer_cut_order = layer_order_top - 1; layer_cut_order > layer_order_bottom; layer_cut_order -= 2) { + idb::IdbSpecialWire* wire_current = wire_list->find_wire(current_wire_index); + if (wire_current == nullptr) { + LOG_INFO << "Error : cannot find wire at index " << current_wire_index; + continue; + } - // Don't support two layers with the same direction - if ((layer_top->is_horizontal() && layer_M2->is_horizontal()) || - (layer_top->is_vertical() && layer_M2->is_vertical())) { - LOG_INFO << "Error : layers have the same direction."; - return nullptr; - } + // Get cut layer + idb::IdbLayerCut* layer_cut = dynamic_cast(idb_layer_list->find_layer_by_order(layer_cut_order)); - // Get network - idb::IdbSpecialNet* net = idb_pdn_list->find_net(net_name); - if (net == nullptr) { - LOG_INFO << "Error : can't find the net " << net_name; - return nullptr; - } + if (layer_cut == nullptr) { + LOG_INFO << "Error : layer input illegal for order " << layer_cut_order; + continue; + } - // Get network wire list - idb::IdbSpecialWireList* wire_list = net->get_wire_list(); - if (wire_list == nullptr) { - LOG_INFO << "Error : not wire in Special net " << net_name; - return nullptr; - } + // Find or create via + idb::IdbVia* via_find = findVia(layer_cut, intersection_rect.get_width(), intersection_rect.get_height()); - std::vector segment_list_top; - std::vector segment_list_bottom; - idb::IdbSpecialWire* wire_top = nullptr; - - // Collect top and bottom layer segments - for (idb::IdbSpecialWire* wire : wire_list->get_wire_list()) { - for (idb::IdbSpecialWireSegment* segment : wire->get_segment_list()) { - if (segment->is_tripe() || segment->is_follow_pin()) { - if (segment->get_layer()->compareLayer(layer_top)) { - segment->set_bounding_box(); - segment_list_top.emplace_back(segment); - // wire_top = wire; - } - if (segment->get_layer()->compareLayer(layer_M2)) { - segment->set_bounding_box(); - segment_list_bottom.emplace_back(segment); + if (via_find == nullptr) { + LOG_INFO << "Error : can not find VIA matches for cut layer " << layer_cut->get_name(); + continue; } - } - } - } - // For each top layer segment - for (idb::IdbSpecialWireSegment* segment_top : segment_list_top) { - // For each bottom layer segment - for (idb::IdbSpecialWireSegment* segment_bottom : segment_list_bottom) { - // Calculate intersection area - idb::IdbRect intersection_rect; - if (getIntersectCoordinate(segment_top, segment_bottom, intersection_rect)) { - - int32_t layer_order_M2 = layer_M2->get_order(); - int32_t layer_order_top = layer_top->get_order(); + // Get via top layer + idb::IdbLayer* layer_top_via = via_find->get_top_layer_shape().get_layer(); - // Create coordinate - idb::IdbCoordinate middle = intersection_rect.get_middle_point(); - idb::IdbCoordinate* middle_ptr = new idb::IdbCoordinate(middle.get_x(), middle.get_y()); + // Create via segment + idb::IdbSpecialWireSegment* segment_via + = createSpecialWireVia(layer_top_via, 0, idb::IdbWireShapeType::kStripe, middle_ptr, via_find); - int wire_top_index = (layer_top->get_order() - layer_M9->get_order()) / (-2); + // Add to wire + wire_current->add_segment(segment_via); - // Process each cut layer - for (int layer_cut_order = layer_order_top - 1; - layer_cut_order > layer_order_M2 - 2; layer_cut_order -= 2) { - - wire_top = wire_list->find_wire(wire_top_index); - - // Get cut layer - idb::IdbLayerCut* layer_cut = dynamic_cast( - idb_layer_list->find_layer_by_order(layer_cut_order)); - - if (layer_cut == nullptr) { - LOG_INFO << "Error : layer input illegal."; - continue; - } - - // Find or create via - idb::IdbVia* via_find = findVia(layer_cut, - intersection_rect.get_width(), - intersection_rect.get_height(), - idb_design); - - if (via_find == nullptr) { - LOG_INFO << "Error : can not find VIA matchs."; - continue; - } - - // Get via top layer - idb::IdbLayer* layer_top_via = via_find->get_top_layer_shape().get_layer(); - - // Create via segment - idb::IdbSpecialWireSegment* segment_via = createSpecialWireVia( - layer_top_via, 0, idb::IdbWireShapeType::kStripe, middle_ptr, via_find); - - // Add to wire - wire_top->add_segment(segment_via); - wire_top_index++; - } + // Move to next wire (next layer down) + current_wire_index++; } } } + } + LOG_INFO << "Success : connectLayers " << top_layer_name << " & " << bottom_layer_name; +} + +void PowerVia::connect_M2_M1(std::string net_name) +{ + auto idb_layout = dmInst->get_idb_layout(); + auto idb_design = dmInst->get_idb_design(); + auto idb_layer_list = idb_layout->get_layers(); + auto idb_pdn_list = idb_design->get_special_net_list(); + auto idb_via_list = idb_design->get_via_list(); + + // Get layer information + idb::IdbLayerRouting* layer_M3 = dynamic_cast(idb_layer_list->find_layer("M3")); + idb::IdbLayerRouting* layer_M2 = dynamic_cast(idb_layer_list->find_layer("M2")); + idb::IdbLayerRouting* layer_M1 = dynamic_cast(idb_layer_list->find_layer("M1")); + idb::IdbLayerCut* layer_via1 = dynamic_cast(idb_layer_list->find_layer("VIA1")); + idb::IdbLayerCut* layer_via2 = dynamic_cast(idb_layer_list->find_layer("VIA2")); + + if (!layer_M3 || !layer_M2 || !layer_M1 || !layer_via1 || !layer_via2) { + LOG_INFO << "Error: Cannot find required layers"; + return; + } - LOG_INFO << "Success : connectLayers " << top_layer_name << " & " << bottom_layer_name; - return idb_design; - } - - idb::IdbDesign* PowerVia::connect_M2_M1(std::string net_name, idb::IdbDesign* idb_design) - { - auto idb_layout = idb_design->get_layout(); - auto idb_layer_list = idb_layout->get_layers(); - auto idb_pdn_list = idb_design->get_special_net_list(); - auto idb_via_list = idb_design->get_via_list(); - - // Get layer information - idb::IdbLayerRouting* layer_M3 = dynamic_cast( - idb_layer_list->find_layer("M3")); - idb::IdbLayerRouting* layer_M2 = dynamic_cast( - idb_layer_list->find_layer("M2")); - idb::IdbLayerRouting* layer_M1 = dynamic_cast( - idb_layer_list->find_layer("M1")); - idb::IdbLayerCut* layer_via1 = dynamic_cast( - idb_layer_list->find_layer("VIA1")); - idb::IdbLayerCut* layer_via2 = dynamic_cast( - idb_layer_list->find_layer("VIA2")); - - if (!layer_M3 || !layer_M2 || !layer_M1 || !layer_via1 || !layer_via2) { - LOG_INFO << "Error: Cannot find required layers"; - return nullptr; - } + // Get network + idb::IdbSpecialNet* net = idb_pdn_list->find_net(net_name); + if (net == nullptr) { + LOG_INFO << "Error : can't find the net " << net_name; + return; + } - // Get network - idb::IdbSpecialNet* net = idb_pdn_list->find_net(net_name); - if (net == nullptr) { - LOG_INFO << "Error : can't find the net " << net_name; - return nullptr; - } + // Get network wire list + idb::IdbSpecialWireList* wire_list = net->get_wire_list(); + if (wire_list == nullptr) { + LOG_INFO << "Error : not wire in Special net " << net_name; + return; + } - // Get network wire list - idb::IdbSpecialWireList* wire_list = net->get_wire_list(); - if (wire_list == nullptr) { - LOG_INFO << "Error : not wire in Special net " << net_name; - return nullptr; - } + // First check if VIAGEN12_RECT_1 via already exists + idb::IdbVia* m2_m1_via = idb_via_list->find_via("VIAGEN12_RECT_1"); - // 首先检查是否已经存在VIAGEN12_RECT_1 via - idb::IdbVia* m2_m1_via = idb_via_list->find_via("VIAGEN12_RECT_1"); - - // 如果不存在,则需要创建 - if (m2_m1_via == nullptr) { - LOG_INFO << "VIAGEN12_RECT_1 not found, creating it..."; - - // 查找M3-M2 via作为模板 - idb::IdbVia* m3_m2_via = nullptr; - - for (auto via : idb_via_list->get_via_list()) { - auto cut_layer_shape = via->get_cut_layer_shape(); - auto cut_layer = cut_layer_shape.get_layer(); - if (cut_layer->compareLayer(layer_via2) && via->get_name().find("VIAGEN23") != std::string::npos) { - m3_m2_via = via; - LOG_INFO << "Found M3-M2 via : " << via->get_name(); - break; - } - } - - if (m3_m2_via) { - // clone via - m2_m1_via = m3_m2_via->clone(); - - // set via master - idb::IdbViaMaster* m2_m1_via_master = m3_m2_via->get_instance()->clone(); - - // set via master generate - idb::IdbViaMasterGenerate* m2_m1_via_master_generate = m2_m1_via_master->get_master_generate()->clone(); - m2_m1_via_master_generate->set_rule_name("VIAGEN12_RECT_1"); - m2_m1_via_master_generate->set_layer_bottom(layer_M1); - m2_m1_via_master_generate->set_layer_top(layer_M2); - m2_m1_via_master_generate->set_layer_cut(layer_via1); - - // set rule generate - idb::IdbViaRuleGenerate* m2_m1_via_rule_generate = m2_m1_via_master_generate->get_rule_generate(); - m2_m1_via_rule_generate->set_name("VIAGEN12_RECT_1"); - m2_m1_via_rule_generate->set_layer_bottom(layer_M1); - m2_m1_via_rule_generate->set_layer_top(layer_M2); - m2_m1_via_rule_generate->set_layer_cut(layer_via1); - - m2_m1_via_master_generate->set_rule_generate(m2_m1_via_rule_generate); - m2_m1_via_master->set_master_generate(m2_m1_via_master_generate); - m2_m1_via->set_instance(m2_m1_via_master); - - // set via name - m2_m1_via->set_name("VIAGEN12_RECT_1"); - - idb_via_list->add_via(m2_m1_via); - - LOG_INFO << "Created new M2-M1 via: VIAGEN12_RECT_1 based on " << m3_m2_via->get_name(); - } else { - LOG_INFO << "Error: Cannot find M3-M2 via template"; - return idb_design; + // If it doesn't exist, need to create it + if (m2_m1_via == nullptr) { + LOG_INFO << "VIAGEN12_RECT_1 not found, creating it..."; + + // Find M3-M2 via as template + idb::IdbVia* m3_m2_via = nullptr; + + for (auto via : idb_via_list->get_via_list()) { + auto cut_layer_shape = via->get_cut_layer_shape(); + auto cut_layer = cut_layer_shape.get_layer(); + if (cut_layer->compareLayer(layer_via2) && via->get_name().find("VIAGEN23") != std::string::npos) { + m3_m2_via = via; + LOG_INFO << "Found M3-M2 via : " << via->get_name(); + break; } - } else { - LOG_INFO << "Using existing VIAGEN12_RECT_1 via for " << net_name; } - // 无论是新创建还是已存在,都使用m2_m1_via添加到网络中 - for (idb::IdbSpecialWire* wire : wire_list->get_wire_list()) { - auto segment_list = wire->get_segment_list(); + if (m3_m2_via) { + // clone via + m2_m1_via = m3_m2_via->clone(); - for (idb::IdbSpecialWireSegment* segment : segment_list) { - if (segment->is_via() && segment->get_layer()->compareLayer(layer_M3)) { - // 在M2层添加通孔 - idb::IdbSpecialWireSegment* new_segment = new idb::IdbSpecialWireSegment(); - new_segment->set_layer(layer_M2); - new_segment->set_is_via(true); - new_segment->set_route_width(0); + // set via master + idb::IdbViaMaster* m2_m1_via_master = m3_m2_via->get_instance()->clone(); - // 使用M2-M1 via - new_segment->set_via(m2_m1_via); + // set via master generate + idb::IdbViaMasterGenerate* m2_m1_via_master_generate = m2_m1_via_master->get_master_generate()->clone(); + m2_m1_via_master_generate->set_rule_name("VIAGEN12_RECT_1"); + m2_m1_via_master_generate->set_layer_bottom(layer_M1); + m2_m1_via_master_generate->set_layer_top(layer_M2); + m2_m1_via_master_generate->set_layer_cut(layer_via1); - // 复制坐标点 - if (!segment->get_point_list().empty()) { - new_segment->add_point(segment->get_point_list()[0]->get_x(), segment->get_point_list()[0]->get_y()); - } + // set rule generate + idb::IdbViaRuleGenerate* m2_m1_via_rule_generate = m2_m1_via_master_generate->get_rule_generate(); + m2_m1_via_rule_generate->set_name("VIAGEN12_RECT_1"); + m2_m1_via_rule_generate->set_layer_bottom(layer_M1); + m2_m1_via_rule_generate->set_layer_top(layer_M2); + m2_m1_via_rule_generate->set_layer_cut(layer_via1); + + m2_m1_via_master_generate->set_rule_generate(m2_m1_via_rule_generate); + m2_m1_via_master->set_master_generate(m2_m1_via_master_generate); + m2_m1_via->set_instance(m2_m1_via_master); + + // set via name + m2_m1_via->set_name("VIAGEN12_RECT_1"); + + idb_via_list->add_via(m2_m1_via); + + LOG_INFO << "Created new M2-M1 via: VIAGEN12_RECT_1 based on " << m3_m2_via->get_name(); + } else { + LOG_INFO << "Error: Cannot find M3-M2 via template"; + return; + } + } else { + LOG_INFO << "Using existing VIAGEN12_RECT_1 via for " << net_name; + } - // 添加到wire中 - wire->add_segment(new_segment); + // Whether newly created or already existing, use m2_m1_via to add to network + for (idb::IdbSpecialWire* wire : wire_list->get_wire_list()) { + auto segment_list = wire->get_segment_list(); + + for (idb::IdbSpecialWireSegment* segment : segment_list) { + if (segment->is_via() && segment->get_layer()->compareLayer(layer_M3)) { + // Add via on M2 layer + idb::IdbSpecialWireSegment* new_segment = new idb::IdbSpecialWireSegment(); + new_segment->set_layer(layer_M2); + new_segment->set_is_via(true); + new_segment->set_route_width(0); + + // Use M2-M1 via + new_segment->set_via(m2_m1_via); + + // Copy coordinate points + if (!segment->get_point_list().empty()) { + new_segment->add_point(segment->get_point_list()[0]->get_x(), segment->get_point_list()[0]->get_y()); } + + // Add to wire + wire->add_segment(new_segment); } } - - return idb_design; } - -} // namespace ipnp \ No newline at end of file +} + +} // namespace ipnp \ No newline at end of file diff --git a/src/operation/iPNP/source/module/synthesis/PowerVia.hh b/src/operation/iPNP/source/module/synthesis/PowerVia.hh index 9d260789a499966ff0dcda86f7af1408f20a830a..10284d37b87062afa348c6af5cf92641bfe7d89b 100644 --- a/src/operation/iPNP/source/module/synthesis/PowerVia.hh +++ b/src/operation/iPNP/source/module/synthesis/PowerVia.hh @@ -17,7 +17,7 @@ /** * @file PowerVia.hh * @author Jianrong Su - * @brief + * @brief * @version 1.0 * @date 2025-06-23 */ @@ -28,73 +28,64 @@ #include #include #include +#include -#include "GridManager.hh" -#include "iPNPCommon.hh" +#include "PNPGridManager.hh" namespace idb { - class IdbDesign; - class IdbSpecialNet; - class IdbSpecialNetList; - class IdbSpecialWireList; - class IdbSpecialWire; - class IdbSpecialWireSegment; - class IdbLayer; - class IdbLayerCut; - class IdbLayerRouting; - class IdbVia; - class IdbPin; - class IdbRect; - class IdbInstance; - - enum class SegmentType : int8_t; - enum class IdbWireShapeType : uint8_t; - enum class IdbOrient : uint8_t; - - template - class IdbCoordinate; +class IdbDesign; +class IdbSpecialNet; +class IdbSpecialNetList; +class IdbSpecialWireList; +class IdbSpecialWire; +class IdbSpecialWireSegment; +class IdbLayer; +class IdbLayerCut; +class IdbLayerRouting; +class IdbVia; +class IdbPin; +class IdbRect; +class IdbInstance; + +enum class SegmentType : int8_t; +enum class IdbWireShapeType : uint8_t; +enum class IdbOrient : uint8_t; + +template +class IdbCoordinate; } // namespace idb namespace ipnp { - class PowerVia - { - public: - PowerVia() = default; - ~PowerVia() = default; - - idb::IdbDesign* connectAllPowerLayers(GridManager& pnp_network, idb::IdbDesign* idb_design); - idb::IdbDesign* connectM2M1Layer(idb::IdbDesign* idb_design); - - private: - - idb::IdbDesign* connectNetworkLayers(GridManager& pnp_network, PowerType net_type, idb::IdbDesign* idb_design); - idb::IdbDesign* connectLayers(std::string net_name, std::string top_layer_name, std::string bottom_layer_name, idb::IdbDesign* idb_design); - idb::IdbDesign* connect_Layer_Row(std::string net_name, std::string top_layer_name, std::string bottom_layer_name, idb::IdbDesign* idb_design); - idb::IdbDesign* connect_M2_M1(std::string net_name, idb::IdbDesign* idb_design); - - - int32_t transUnitDB(double value, idb::IdbDesign* idb_design); - - idb::IdbVia* findVia(idb::IdbLayerCut* layer_cut, int32_t width_design, int32_t height_design, idb::IdbDesign* idb_design); - - idb::IdbVia* createVia(idb::IdbLayerCut* layer_cut, int32_t width_design, int32_t height_design, std::string via_name, idb::IdbDesign* idb_design); - - idb::IdbSpecialWireSegment* createSpecialWireVia(idb::IdbLayer* layer, int32_t route_width, - idb::IdbWireShapeType wire_shape_type, - idb::IdbCoordinate* coord, - idb::IdbVia* via); - - bool getIntersectCoordinate(idb::IdbSpecialWireSegment* segment_top, - idb::IdbSpecialWireSegment* segment_bottom, - idb::IdbRect& intersection_rect); - - bool addSingleVia(std::string net_name, - std::string top_layer, - std::string bottom_layer, - double x, double y, - int32_t width, int32_t height, - idb::IdbDesign* idb_design); - }; - -} // namespace ipnp \ No newline at end of file +class PowerVia +{ + public: + PowerVia() = default; + ~PowerVia() = default; + + void connectAllPowerLayers(PNPGridManager& pnp_network); + void connectM2M1Layer(); + + private: + void connectNetworkLayers(PNPGridManager& pnp_network, PowerType net_type); + void connectLayers(std::string net_name, std::string top_layer_name, std::string bottom_layer_name); + void connect_Layer_Row(std::string net_name, std::string top_layer_name, std::string bottom_layer_name); + void connect_M2_M1(std::string net_name); + + int32_t transUnitDB(double value); + + idb::IdbVia* findVia(idb::IdbLayerCut* layer_cut, int32_t width_design, int32_t height_design); + + idb::IdbVia* createVia(idb::IdbLayerCut* layer_cut, int32_t width_design, int32_t height_design, std::string via_name); + + idb::IdbSpecialWireSegment* createSpecialWireVia(idb::IdbLayer* layer, int32_t route_width, idb::IdbWireShapeType wire_shape_type, + idb::IdbCoordinate* coord, idb::IdbVia* via); + + bool getIntersectCoordinate(idb::IdbSpecialWireSegment* segment_top, idb::IdbSpecialWireSegment* segment_bottom, + idb::IdbRect& intersection_rect); + + bool addSingleVia(std::string net_name, std::string top_layer, std::string bottom_layer, double x, double y, int32_t width, + int32_t height); +}; + +} // namespace ipnp \ No newline at end of file diff --git a/src/operation/iPNP/test/CMakeLists.txt b/src/operation/iPNP/test/CMakeLists.txt deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/operation/iRT/CMakeLists.txt b/src/operation/iRT/CMakeLists.txt index edf44c092c78f98854ba13738239b3f0b53cd176..582b405f985587042ad85c2302dee280233f44f0 100644 --- a/src/operation/iRT/CMakeLists.txt +++ b/src/operation/iRT/CMakeLists.txt @@ -5,9 +5,9 @@ message(STATUS "############## RT: START CMAKE ##############") set(CMAKE_CXX_STANDARD 20) -# ADD_COMPILE_OPTIONS("-Wconversion") -# ADD_COMPILE_OPTIONS("-fsanitize=address") -# LINK_LIBRARIES("-fsanitize=address") +# add_compile_options("-Wconversion") +# add_compile_options("-fsanitize=address") +# link_libraries("-fsanitize=address") ############################ debug interface ############################ diff --git a/src/operation/iRT/README.md b/src/operation/iRT/README.md index 51deeec67cc82ec281ddea3e0bee7e9ce1690564..8e685968edbc8f45d01577fed0826739fceafbda 100644 --- a/src/operation/iRT/README.md +++ b/src/operation/iRT/README.md @@ -1,46 +1,45 @@ -# iRT 介绍 +# iRT: Routing -## 背景 +## Background -iPower-structure +iRT-structure -布线是继布局和时钟树综合之后的重要物理实施任务,其内容是将分布在芯片核内的模块,标准单元和输入输出接口单元按逻辑关系进行互连,并为满足各种约束条件进行优化。iRT是iEDA课题组针对布线阶段设计的一款布线器,其内部集成了全局布线和详细布线。 +Wiring is an important physical implementation task after layout and clock tree synthesis. Its content is to interconnect the modules, standard cells, and input/output interface units distributed in the chip core according to the logical relationship, and optimize to meet various constraint conditions. iRT is a wire router designed for the wiring stage by the iEDA research group, and it integrates global wiring and detailed wiring internally. -## 软件结构 +## Software Structure iPower-structure -### API:多种语言的iRT接口 +### API: iRT interfaces in multiple languages iPower-structure -### data manager:顶层数据管理器 +### Data Manager: Top-level data manager -### module:算法主要模块 +### Module: Main algorithm modules -- pin_accessor: 对所有pin分配access点,在port上找到可以接入的点 +- Pin_accessor: Allocates access points for all pins and finds accessible points on the port -- space_router: 全局布线器,以GCell为单位,在三维网格上进行全局布线 +- Global_router: Global router, in units of GCell, performs global wiring on a three-dimensional grid -- track_assigner: wire轨道分配,建模为布线问题进行轨道分配 +- Track_assigner: Wire track assignment, modeled as a wiring problem for track assignment -- detailed_router: 详细布线器,以DRC驱动的,基于三维track网格的详细布线器 +- Detailed_router: Detailed router, a DRC-driven detailed router based on a three-dimensional track grid -### solver:布线时可以使用的求解器 +### Solver: Solvers that can be used during wiring -- flute: 以查找表的形式进行快速斯坦纳树生成 +- Flute: Generates fast Steiner trees in the form of lookup tables -- A*: 三维路径搜索算法 +- A*: Three-dimensional path search algorithm -### utility:工具模块 +### Utility: Tool modules -- logger: 日志模块 +- Logger: Log module -- monitor: 运行状态监视器 +- Monitor: Runtime status monitor -- report: 报告器 +- Report: Reporter -- util: 工具函数 - -- plotter: debug可视化模块 +- Util: Utility functions +- Plotter: Debug visualization module \ No newline at end of file diff --git a/src/operation/iRT/interface/CMakeLists.txt b/src/operation/iRT/interface/CMakeLists.txt index 92ec81a65fd4b68558d6faa67020e92f9bb0b442..93181805115b6ea233f0e851aaa0b7aee1d33789 100644 --- a/src/operation/iRT/interface/CMakeLists.txt +++ b/src/operation/iRT/interface/CMakeLists.txt @@ -1,8 +1,8 @@ -if(DEBUG_IRT_INTERFACE) - message(STATUS "RT: DEBUG_IRT_INTERFACE") +if(DEBUG_IRT_INTERFACE) + message(STATUS "RT: DEBUG_IRT_INTERFACE") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_INTERFACE") + message(STATUS "RT: RELEASE_IRT_INTERFACE") set(CMAKE_BUILD_TYPE "Release") endif() @@ -12,15 +12,16 @@ add_library(irt_interface target_link_libraries(irt_interface PRIVATE - irt_source - idrc_interface - ls_assigner - power - ieda_feature - idm + irt_source + idrc_interface + ls_assigner + power + ieda_feature + idm + notification ) target_include_directories(irt_interface PUBLIC - ${IRT_INTERFACE} + ${IRT_INTERFACE} ) diff --git a/src/operation/iRT/interface/RTInterface.cpp b/src/operation/iRT/interface/RTInterface.cpp index 77ed7c4e0c541935391e5e7ade21f5cdbfa8c168..dde3e2081ef8d375dc1df2a647a1a64c8862f446 100644 --- a/src/operation/iRT/interface/RTInterface.cpp +++ b/src/operation/iRT/interface/RTInterface.cpp @@ -24,6 +24,7 @@ #include "LSAssigner4iEDA/ls_assigner/LSAssigner.h" #include "LayerAssigner.hpp" #include "Monitor.hpp" +#include "NotificationUtility.h" #include "PinAccessor.hpp" #include "RTInterface.hpp" #include "SpaceRouter.hpp" @@ -277,6 +278,241 @@ void RTInterface::clearDef() ////////////////////////////////////////// } +void RTInterface::outputDBJson(std::map config_map) +{ + std::string stage = RTUTIL.getConfigValue(config_map, "-stage", "null"); + if (stage == "null") { + std::cout << "The stage is null!" << std::endl; + return; + } + if (stage == "fp") { + idb::IdbDie* idb_die = dmInst->get_idb_lef_service()->get_layout()->get_die(); + std::vector& idb_instance_list = dmInst->get_idb_def_service()->get_design()->get_instance_list()->get_instance_list(); + idb::IdbRows* idb_rows = dmInst->get_idb_def_service()->get_layout()->get_rows(); + std::vector& idb_layers = dmInst->get_idb_lef_service()->get_layout()->get_layers()->get_layers(); + + std::vector db_json_list; + { + nlohmann::json die_json; + die_json["die"] = {idb_die->get_llx(), idb_die->get_lly(), idb_die->get_urx(), idb_die->get_ury()}; + db_json_list.push_back(die_json); + } + { + for (idb::IdbInstance* idb_instance : idb_instance_list) { + if (!idb_instance->is_fixed()) { + continue; + } + nlohmann::json instance_json; + instance_json["name"] = idb_instance->get_name(); + instance_json["bbox"] = {idb_instance->get_bounding_box()->get_low_x(), idb_instance->get_bounding_box()->get_low_y(), + idb_instance->get_bounding_box()->get_high_x(), idb_instance->get_bounding_box()->get_high_y()}; + std::set layer_name_set; + for (idb::IdbObs* idb_obs : idb_instance->get_cell_master()->get_obs_list()) { + for (idb::IdbObsLayer* idb_layer : idb_obs->get_obs_layer_list()) { + layer_name_set.insert(idb_layer->get_shape()->get_layer()->get_name()); + } + } + for (idb::IdbLayerShape* obs_box : idb_instance->get_obs_box_list()) { + layer_name_set.insert(obs_box->get_layer()->get_name()); + } + for (idb::IdbPin* idb_pin : idb_instance->get_pin_list()->get_pin_list()) { + for (idb::IdbLayerShape* port_box : idb_pin->get_port_box_list()) { + layer_name_set.insert(port_box->get_layer()->get_name()); + } + for (idb::IdbVia* idb_via : idb_pin->get_via_list()) { + idb::IdbLayerShape idb_shape_top = idb_via->get_top_layer_shape(); + layer_name_set.insert(idb_shape_top.get_layer()->get_name()); + idb::IdbLayerShape idb_shape_bottom = idb_via->get_bottom_layer_shape(); + layer_name_set.insert(idb_shape_bottom.get_layer()->get_name()); + idb::IdbLayerShape idb_shape_cut = idb_via->get_cut_layer_shape(); + layer_name_set.insert(idb_shape_cut.get_layer()->get_name()); + } + } + instance_json["layer"] = layer_name_set; + instance_json["type"] = ((idb_instance->get_cell_master()->get_type() == idb::CellMasterType::kPad) ? "io_cell" : "core"); + db_json_list.push_back(instance_json); + } + } + { + std::string layer_name = "null"; + for (idb::IdbLayer* idb_layer : idb_layers) { + if (idb_layer->is_routing()) { + idb::IdbLayerRouting* idb_routing_layer = dynamic_cast(idb_layer); + layer_name = idb_routing_layer->get_name(); + break; + } + } + for (idb::IdbRow* idb_row : idb_rows->get_row_list()) { + idb::IdbCoordinate* idb_coord = idb_row->get_original_coordinate(); + nlohmann::json row_json; + row_json["name"] = idb_row->get_name(); + row_json["bbox"] + = {idb_coord->get_x(), idb_coord->get_y(), idb_coord->get_x() + (idb_row->get_row_num_x() * idb_row->get_step_x()), idb_coord->get_y()}; + row_json["layer"] = layer_name; + row_json["type"] = "row"; + db_json_list.push_back(row_json); + } + } + std::string db_json_file_path = RTUTIL.getString(RTUTIL.getConfigValue(config_map, "-json_file_path", "null")); + std::ofstream* db_json_file = RTUTIL.getOutputFileStream(db_json_file_path); + (*db_json_file) << db_json_list; + RTUTIL.closeFileStream(db_json_file); + } + + { + // std::vector db_json_list; + // { + // nlohmann::json die_json; + // die_json["die"] = {idb_die->get_llx(), idb_die->get_lly(), idb_die->get_urx(), idb_die->get_ury()}; + // db_json_list.push_back(die_json); + // } + // { + // nlohmann::json env_shape_json; + // // instance + // for (idb::IdbInstance* idb_instance : idb_instance_list) { + // if (idb_instance->is_unplaced()) { + // continue; + // } + // if (idb_instance->get_cell_master()->is_pad() || idb_instance->get_cell_master()->is_pad_filler()) { + // idb_instance->get_name(); + // idb_instance->get_bounding_box(); + + // } else { + // // instance obs + // for (idb::IdbLayerShape* obs_box : idb_instance->get_obs_box_list()) { + // for (idb::IdbRect* rect : obs_box->get_rect_list()) { + // env_shape_json["env_shape"]["obs"]["shape"].push_back( + // {rect->get_low_x(), rect->get_low_y(), rect->get_high_x(), rect->get_high_y(), obs_box->get_layer()->get_name()}); + // } + // } + // // instance pin without net + // for (idb::IdbPin* idb_pin : idb_instance->get_pin_list()->get_pin_list()) { + // std::string net_name; + // if (!isSkipping(idb_pin->get_net(), false)) { + // net_name = idb_pin->get_net()->get_net_name(); + // } else { + // net_name = "obs"; + // } + // for (idb::IdbLayerShape* port_box : idb_pin->get_port_box_list()) { + // for (idb::IdbRect* rect : port_box->get_rect_list()) { + // env_shape_json["env_shape"][net_name]["shape"].push_back( + // {rect->get_low_x(), rect->get_low_y(), rect->get_high_x(), rect->get_high_y(), port_box->get_layer()->get_name()}); + // } + // } + // for (idb::IdbVia* idb_via : idb_pin->get_via_list()) { + // { + // idb::IdbLayerShape idb_shape_top = idb_via->get_top_layer_shape(); + // idb::IdbRect idb_box_top = idb_shape_top.get_bounding_box(); + // env_shape_json["env_shape"][net_name]["shape"].push_back({idb_box_top.get_low_x(), idb_box_top.get_low_y(), idb_box_top.get_high_x(), + // idb_box_top.get_high_y(), idb_shape_top.get_layer()->get_name()}); + // } + // { + // idb::IdbLayerShape idb_shape_bottom = idb_via->get_bottom_layer_shape(); + // idb::IdbRect idb_box_bottom = idb_shape_bottom.get_bounding_box(); + // env_shape_json["env_shape"][net_name]["shape"].push_back({idb_box_bottom.get_low_x(), idb_box_bottom.get_low_y(), + // idb_box_bottom.get_high_x(), + // idb_box_bottom.get_high_y(), idb_shape_bottom.get_layer()->get_name()}); + // } + // idb::IdbLayerShape idb_shape_cut = idb_via->get_cut_layer_shape(); + // for (idb::IdbRect* idb_rect : idb_shape_cut.get_rect_list()) { + // env_shape_json["env_shape"][net_name]["shape"].push_back( + // {idb_rect->get_low_x(), idb_rect->get_low_y(), idb_rect->get_high_x(), idb_rect->get_high_y(), idb_shape_cut.get_layer()->get_name()}); + // } + // } + // } + // } + // } + // // special net + // for (idb::IdbSpecialNet* idb_net : idb_special_net_list) { + // for (idb::IdbSpecialWire* idb_wire : idb_net->get_wire_list()->get_wire_list()) { + // for (idb::IdbSpecialWireSegment* idb_segment : idb_wire->get_segment_list()) { + // if (idb_segment->is_via()) { + // for (idb::IdbLayerShape layer_shape : {idb_segment->get_via()->get_top_layer_shape(), idb_segment->get_via()->get_bottom_layer_shape()}) { + // for (idb::IdbRect* rect : layer_shape.get_rect_list()) { + // env_shape_json["env_shape"]["obs"]["shape"].push_back( + // {rect->get_low_x(), rect->get_low_y(), rect->get_high_x(), rect->get_high_y(), layer_shape.get_layer()->get_name()}); + // } + // } + // idb::IdbLayerShape cut_layer_shape = idb_segment->get_via()->get_cut_layer_shape(); + // for (idb::IdbRect* rect : cut_layer_shape.get_rect_list()) { + // env_shape_json["env_shape"]["obs"]["shape"].push_back( + // {rect->get_low_x(), rect->get_low_y(), rect->get_high_x(), rect->get_high_y(), cut_layer_shape.get_layer()->get_name()}); + // } + // } else { + // idb::IdbRect* idb_rect = idb_segment->get_bounding_box(); + // // wire + // env_shape_json["env_shape"]["obs"]["shape"].push_back( + // {idb_rect->get_low_x(), idb_rect->get_low_y(), idb_rect->get_high_x(), idb_rect->get_high_y(), idb_segment->get_layer()->get_name()}); + // } + // } + // } + // } + // // io pin + // for (idb::IdbPin* idb_io_pin : idb_io_pin_list) { + // std::string net_name; + // if (!isSkipping(idb_io_pin->get_net(), false)) { + // net_name = idb_io_pin->get_net()->get_net_name(); + // } else { + // net_name = "obs"; + // } + // for (idb::IdbLayerShape* port_box : idb_io_pin->get_port_box_list()) { + // for (idb::IdbRect* rect : port_box->get_rect_list()) { + // env_shape_json["env_shape"][net_name]["shape"].push_back( + // {rect->get_low_x(), rect->get_low_y(), rect->get_high_x(), rect->get_high_y(), port_box->get_layer()->get_name()}); + // } + // } + // } + // db_json_list.push_back(env_shape_json); + // } + // { + // nlohmann::json result_shape_json; + // // net + // for (idb::IdbNet* idb_net : idb_net_list) { + // for (idb::IdbRegularWire* idb_wire : idb_net->get_wire_list()->get_wire_list()) { + // for (idb::IdbRegularWireSegment* idb_segment : idb_wire->get_segment_list()) { + // if (idb_segment->get_point_number() >= 2) { + // PlanarCoord first_coord(idb_segment->get_point_start()->get_x(), idb_segment->get_point_start()->get_y()); + // PlanarCoord second_coord(idb_segment->get_point_second()->get_x(), idb_segment->get_point_second()->get_y()); + // int32_t half_width = dynamic_cast(idb_segment->get_layer())->get_width() / 2; + // PlanarRect rect = RTUTIL.getEnlargedRect(first_coord, second_coord, half_width); + // result_shape_json["result_shape"][idb_net->get_net_name()]["path"].push_back( + // {rect.get_ll_x(), rect.get_ll_y(), rect.get_ur_x(), rect.get_ur_y(), idb_segment->get_layer()->get_name()}); + // } + // if (idb_segment->is_via()) { + // for (idb::IdbVia* idb_via : idb_segment->get_via_list()) { + // for (idb::IdbLayerShape layer_shape : {idb_via->get_top_layer_shape(), idb_via->get_bottom_layer_shape()}) { + // for (idb::IdbRect* rect : layer_shape.get_rect_list()) { + // result_shape_json["result_shape"][idb_net->get_net_name()]["path"].push_back( + // {rect->get_low_x(), rect->get_low_y(), rect->get_high_x(), rect->get_high_y(), layer_shape.get_layer()->get_name()}); + // } + // } + // idb::IdbLayerShape cut_layer_shape = idb_via->get_cut_layer_shape(); + // for (idb::IdbRect* rect : cut_layer_shape.get_rect_list()) { + // result_shape_json["result_shape"][idb_net->get_net_name()]["path"].push_back( + // {rect->get_low_x(), rect->get_low_y(), rect->get_high_x(), rect->get_high_y(), cut_layer_shape.get_layer()->get_name()}); + // } + // } + // } + // if (idb_segment->is_rect()) { + // PlanarCoord offset_coord(idb_segment->get_point_start()->get_x(), idb_segment->get_point_start()->get_y()); + // PlanarRect delta_rect(idb_segment->get_delta_rect()->get_low_x(), idb_segment->get_delta_rect()->get_low_y(), + // idb_segment->get_delta_rect()->get_high_x(), idb_segment->get_delta_rect()->get_high_y()); + // PlanarRect rect = RTUTIL.getOffsetRect(delta_rect, offset_coord); + // result_shape_json["result_shape"][idb_net->get_net_name()]["patch"].push_back( + // {rect.get_ll_x(), rect.get_ll_y(), rect.get_ur_x(), rect.get_ur_y(), idb_segment->get_layer()->get_name()}); + // } + // } + // } + // } + // db_json_list.push_back(result_shape_json); + // } + // std::string db_json_file_path = RTUTIL.getString(RTUTIL.getConfigValue(config_map, "-json_file_path", "null")); + // std::ofstream* db_json_file = RTUTIL.getOutputFileStream(db_json_file_path); + // (*db_json_file) << db_json_list; + // RTUTIL.closeFileStream(db_json_file); + } +} + #endif #endif @@ -302,6 +538,7 @@ void RTInterface::wrapConfig(std::map& config_map) RTDM.getConfig().bottom_routing_layer = RTUTIL.getConfigValue(config_map, "-bottom_routing_layer", ""); RTDM.getConfig().top_routing_layer = RTUTIL.getConfigValue(config_map, "-top_routing_layer", ""); RTDM.getConfig().output_inter_result = RTUTIL.getConfigValue(config_map, "-output_inter_result", 0); + RTDM.getConfig().enable_notification = RTUTIL.getConfigValue(config_map, "-enable_notification", 0); RTDM.getConfig().enable_timing = RTUTIL.getConfigValue(config_map, "-enable_timing", 0); RTDM.getConfig().enable_fast_mode = RTUTIL.getConfigValue(config_map, "-enable_fast_mode", 0); RTDM.getConfig().enable_lsa = RTUTIL.getConfigValue(config_map, "-enable_lsa", 0); @@ -319,7 +556,6 @@ void RTInterface::wrapDatabase() wrapLayerInfo(); wrapLayerViaMasterList(); wrapObstacleList(); - wrapNetInfo(); wrapNetList(); } @@ -396,20 +632,13 @@ void RTInterface::wrapTrackAxis(RoutingLayer& routing_layer, idb::IdbLayerRoutin { ScaleAxis& track_axis = routing_layer.get_track_axis(); - for (idb::IdbTrackGrid* idb_track_grid : idb_layer->get_track_grid_list()) { - idb::IdbTrack* idb_track = idb_track_grid->get_track(); + ScaleGrid x_track_grid; + x_track_grid.set_step_length(idb_layer->get_pitch_x()); + track_axis.get_x_grid_list().push_back(x_track_grid); - ScaleGrid track_grid; - track_grid.set_start_line(static_cast(idb_track->get_start())); - track_grid.set_step_length(static_cast(idb_track->get_pitch())); - track_grid.set_step_num(static_cast(idb_track_grid->get_track_num()) - 1); - - if (idb_track->get_direction() == idb::IdbTrackDirection::kDirectionX) { - track_axis.get_x_grid_list().push_back(track_grid); - } else if (idb_track->get_direction() == idb::IdbTrackDirection::kDirectionY) { - track_axis.get_y_grid_list().push_back(track_grid); - } - } + ScaleGrid y_track_grid; + y_track_grid.set_step_length(idb_layer->get_pitch_y()); + track_axis.get_y_grid_list().push_back(y_track_grid); } void RTInterface::wrapRoutingDesignRule(RoutingLayer& routing_layer, idb::IdbLayerRouting* idb_layer) @@ -841,23 +1070,6 @@ void RTInterface::wrapObstacleList() RTLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); } -void RTInterface::wrapNetInfo() -{ - std::map& block_shape_map = RTDM.getDatabase().get_block_shape_map(); - std::vector& idb_instance_list = dmInst->get_idb_def_service()->get_design()->get_instance_list()->get_instance_list(); - - for (idb::IdbInstance* idb_instance : idb_instance_list) { - if (idb_instance->get_cell_master()->is_core()) { - continue; - } - if (idb_instance->get_connected_pin_number() == 0) { - continue; - } - idb::IdbRect* idb_shape = idb_instance->get_bounding_box(); - block_shape_map[idb_instance->get_name()] = {idb_shape->get_low_x(), idb_shape->get_low_y(), idb_shape->get_high_x(), idb_shape->get_high_y()}; - } -} - void RTInterface::wrapNetList() { Monitor monitor; @@ -1185,8 +1397,6 @@ void RTInterface::outputSummary() { for (auto& [iter, pa_summary] : rt_summary.iter_pa_summary_map) { ieda_feature::PASummary& top_pa_summary = top_rt_summary.iter_pa_summary_map[iter]; - top_pa_summary.routing_access_point_num_map = pa_summary.routing_access_point_num_map; - top_pa_summary.total_access_point_num = pa_summary.total_access_point_num; top_pa_summary.routing_wire_length_map = pa_summary.routing_wire_length_map; top_pa_summary.total_wire_length = pa_summary.total_wire_length; top_pa_summary.cut_via_num_map = pa_summary.cut_via_num_map; @@ -1207,8 +1417,8 @@ void RTInterface::outputSummary() top_rt_summary.tg_summary.total_demand = rt_summary.tg_summary.total_demand; top_rt_summary.tg_summary.total_overflow = rt_summary.tg_summary.total_overflow; top_rt_summary.tg_summary.total_wire_length = rt_summary.tg_summary.total_wire_length; - top_rt_summary.tg_summary.clock_timing = rt_summary.tg_summary.clock_timing; - top_rt_summary.tg_summary.power_map = rt_summary.tg_summary.power_map; + top_rt_summary.tg_summary.clock_timing_map = rt_summary.tg_summary.clock_timing_map; + top_rt_summary.tg_summary.type_power_map = rt_summary.tg_summary.type_power_map; } // la_summary { @@ -1220,8 +1430,8 @@ void RTInterface::outputSummary() top_rt_summary.la_summary.total_wire_length = rt_summary.la_summary.total_wire_length; top_rt_summary.la_summary.cut_via_num_map = rt_summary.la_summary.cut_via_num_map; top_rt_summary.la_summary.total_via_num = rt_summary.la_summary.total_via_num; - top_rt_summary.la_summary.clock_timing = rt_summary.la_summary.clock_timing; - top_rt_summary.la_summary.power_map = rt_summary.la_summary.power_map; + top_rt_summary.la_summary.clock_timing_map = rt_summary.la_summary.clock_timing_map; + top_rt_summary.la_summary.type_power_map = rt_summary.la_summary.type_power_map; } // sr_summary { @@ -1235,8 +1445,8 @@ void RTInterface::outputSummary() top_sr_summary.total_wire_length = sr_summary.total_wire_length; top_sr_summary.cut_via_num_map = sr_summary.cut_via_num_map; top_sr_summary.total_via_num = sr_summary.total_via_num; - top_sr_summary.clock_timing = sr_summary.clock_timing; - top_sr_summary.power_map = sr_summary.power_map; + top_sr_summary.clock_timing_map = sr_summary.clock_timing_map; + top_sr_summary.type_power_map = sr_summary.type_power_map; } } // ta_summary @@ -1258,8 +1468,8 @@ void RTInterface::outputSummary() top_dr_summary.total_patch_num = dr_summary.total_patch_num; top_dr_summary.routing_violation_num_map = dr_summary.routing_violation_num_map; top_dr_summary.total_violation_num = dr_summary.total_violation_num; - top_dr_summary.clock_timing = dr_summary.clock_timing; - top_dr_summary.power_map = dr_summary.power_map; + top_dr_summary.clock_timing_map = dr_summary.clock_timing_map; + top_dr_summary.type_power_map = dr_summary.type_power_map; } } // vr_summary @@ -1278,8 +1488,8 @@ void RTInterface::outputSummary() top_rt_summary.vr_summary.among_net_violation_type_num_map = rt_summary.vr_summary.among_net_violation_type_num_map; top_rt_summary.vr_summary.among_net_routing_violation_num_map = rt_summary.vr_summary.among_net_routing_violation_num_map; top_rt_summary.vr_summary.among_net_total_violation_num = rt_summary.vr_summary.among_net_total_violation_num; - top_rt_summary.vr_summary.clock_timing = rt_summary.vr_summary.clock_timing; - top_rt_summary.vr_summary.power_map = rt_summary.vr_summary.power_map; + top_rt_summary.vr_summary.clock_timing_map = rt_summary.vr_summary.clock_timing_map; + top_rt_summary.vr_summary.type_power_map = rt_summary.vr_summary.type_power_map; } // er_summary { @@ -1291,8 +1501,8 @@ void RTInterface::outputSummary() top_rt_summary.er_summary.total_wire_length = rt_summary.er_summary.total_wire_length; top_rt_summary.er_summary.cut_via_num_map = rt_summary.er_summary.cut_via_num_map; top_rt_summary.er_summary.total_via_num = rt_summary.er_summary.total_via_num; - top_rt_summary.er_summary.clock_timing = rt_summary.er_summary.clock_timing; - top_rt_summary.er_summary.power_map = rt_summary.er_summary.power_map; + top_rt_summary.er_summary.clock_timing_map = rt_summary.er_summary.clock_timing_map; + top_rt_summary.er_summary.type_power_map = rt_summary.er_summary.type_power_map; } } @@ -1412,7 +1622,8 @@ void RTInterface::destroyIDRC() std::vector RTInterface::getViolationList(std::vector>& env_shape_list, std::map>>& net_pin_shape_map, std::map*>>& net_result_map, - std::map>& net_patch_map) + std::map>& net_patch_map, std::set& check_type_set, + std::vector& check_region_list) { std::vector ids_env_shape_list; for (std::pair& env_shape : env_shape_list) { @@ -1426,7 +1637,7 @@ std::vector RTInterface::getViolationList(std::vector ids_result_shape_list; for (auto& [net_idx, segment_list] : net_result_map) { for (Segment* segment : segment_list) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { ids_result_shape_list.emplace_back(getIDSShape(net_idx, LayerRect(net_shape), net_shape.get_is_routing())); } } @@ -1436,9 +1647,17 @@ std::vector RTInterface::getViolationList(std::vectorgetRealLayerRect(), true)); } } + std::set ids_check_type_set; + for (const ViolationType& check_type : check_type_set) { + ids_check_type_set.insert(GetViolationTypeName()(check_type)); + } + std::vector ids_check_region_list; + for (LayerRect& check_region : check_region_list) { + ids_check_region_list.emplace_back(getIDSShape(-1, check_region, true)); + } std::vector ids_violation_list; { - ids_violation_list = DRCI.getViolationList(ids_env_shape_list, ids_result_shape_list); + ids_violation_list = DRCI.getViolationList(ids_env_shape_list, ids_result_shape_list, ids_check_type_set, ids_check_region_list); } std::vector violation_list; for (ids::Violation& ids_violation : ids_violation_list) { @@ -1885,10 +2104,21 @@ void RTInterface::routeTAPanel(TAPanel& ta_panel) #if 1 // ecos -void RTInterface::sendNotification(std::string stage, std::string json_path) +void RTInterface::sendNotification(std::string stage, int32_t iter, std::map json_path_map) { - std::cout << "stage: " << stage << std::endl; - std::cout << "json_path: " << json_path << std::endl; + std::map notification; + notification["step_name"] = "routing"; + notification["stage"] = stage; + notification["iter"] = std::to_string(iter); + notification["json_path_map"] = json_path_map; + if (!ieda::NotificationUtility::getInstance().sendNotification("iRT", notification).success) { + RTLOG.warn(Loc::current(), "Failed to send notification at stage :", stage, " iter :", iter); + } else { + RTLOG.info(Loc::current(), "Successfully sent notification at stage :", stage, " iter :", iter); + } + for (auto& [key, value] : json_path_map) { + RTLOG.info(Loc::current(), " ", key, " : ", value); + } } #endif diff --git a/src/operation/iRT/interface/RTInterface.hpp b/src/operation/iRT/interface/RTInterface.hpp index 3af2a54b4f12f28a796818d2a74dbaf85a96c015..b7bbacf0cc0b14fef60b7ada5b06b678d70f69c4 100644 --- a/src/operation/iRT/interface/RTInterface.hpp +++ b/src/operation/iRT/interface/RTInterface.hpp @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include @@ -40,6 +41,7 @@ namespace irt { class RoutingLayer; class CutLayer; class Violation; +enum class ViolationType; class LayerCoord; class LayerRect; template @@ -78,6 +80,7 @@ class RTInterface void runRT(); void destroyRT(); void clearDef(); + void outputDBJson(std::map config_map); #endif #endif @@ -102,7 +105,6 @@ class RTInterface void wrapLayerInfo(); void wrapLayerViaMasterList(); void wrapObstacleList(); - void wrapNetInfo(); void wrapNetList(); bool isSkipping(idb::IdbNet* idb_net, bool with_log); void wrapPinList(Net& net, idb::IdbNet* idb_net); @@ -135,7 +137,8 @@ class RTInterface std::vector getViolationList(std::vector>& env_shape_list, std::map>>& net_pin_shape_map, std::map*>>& net_result_map, - std::map>& net_patch_map); + std::map>& net_patch_map, std::set& check_type_set, + std::vector& check_region_list); ids::Shape getIDSShape(int32_t net_idx, LayerRect layer_rect, bool is_routing); #endif @@ -156,7 +159,7 @@ class RTInterface #endif #if 1 // ecos - void sendNotification(std::string stage, std::string json_path); + void sendNotification(std::string stage, int32_t iter, std::map json_path_map); #endif #endif diff --git a/src/operation/iRT/source/CMakeLists.txt b/src/operation/iRT/source/CMakeLists.txt index c3be8dd2ca5b6bafffece851768aab0c46712a75..35f1bc16b2fcc6959c2375bbe5a63a250f7a3167 100644 --- a/src/operation/iRT/source/CMakeLists.txt +++ b/src/operation/iRT/source/CMakeLists.txt @@ -12,7 +12,7 @@ add_library(irt_source INTERFACE) target_link_libraries(irt_source INTERFACE - irt_data_manager - irt_module - irt_toolkit + irt_data_manager + irt_module + irt_toolkit ) diff --git a/src/operation/iRT/source/data_manager/CMakeLists.txt b/src/operation/iRT/source/data_manager/CMakeLists.txt index 92d47234993a1744a853884d79debf6ae9482d99..e7760e4890b5cf66d9b3a59325f992003266a93c 100644 --- a/src/operation/iRT/source/data_manager/CMakeLists.txt +++ b/src/operation/iRT/source/data_manager/CMakeLists.txt @@ -1,8 +1,8 @@ -if(DEBUG_IRT_DATA_MANAGER) - message(STATUS "RT: DEBUG_IRT_DATA_MANAGER") +if(DEBUG_IRT_DATA_MANAGER) + message(STATUS "RT: DEBUG_IRT_DATA_MANAGER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_DATA_MANAGER") + message(STATUS "RT: RELEASE_IRT_DATA_MANAGER") set(CMAKE_BUILD_TYPE "Release") endif() @@ -10,14 +10,14 @@ add_library(irt_data_manager ${IRT_DATA_MANAGER}/DataManager.cpp ) -target_link_libraries(irt_data_manager +target_link_libraries(irt_data_manager PUBLIC - irt_toolkit + irt_toolkit ) -target_include_directories(irt_data_manager +target_include_directories(irt_data_manager PUBLIC - ${IRT_DATA_MANAGER}/advance - ${IRT_DATA_MANAGER}/basic - ${IRT_DATA_MANAGER} + ${IRT_DATA_MANAGER}/advance + ${IRT_DATA_MANAGER}/basic + ${IRT_DATA_MANAGER} ) diff --git a/src/operation/iRT/source/data_manager/DataManager.cpp b/src/operation/iRT/source/data_manager/DataManager.cpp index d4ba2f56df49b1ca0ac90dc0b72297940e85a6df..5685793c7782d33968d7e7fd322a439548733ebd 100644 --- a/src/operation/iRT/source/data_manager/DataManager.cpp +++ b/src/operation/iRT/source/data_manager/DataManager.cpp @@ -59,7 +59,8 @@ void DataManager::input(std::map& config_map) buildDatabase(); printConfig(); printDatabase(); - writePYScript(); + outputScript(); + outputJson(); RTLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); } @@ -149,7 +150,7 @@ void DataManager::updateNetPinAccessResultToGCellMap(ChangeType change_type, int if (detection_distance == -1) { RTLOG.error(Loc::current(), "The detection_distance is not initialize!"); } - for (NetShape& net_shape : getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : getNetDetailedShapeList(net_idx, *segment)) { PlanarRect real_rect = RTUTIL.getEnlargedRect(net_shape, detection_distance); if (!RTUTIL.hasRegularRect(real_rect, die.get_real_rect())) { continue; @@ -258,7 +259,7 @@ void DataManager::updateNetDetailedResultToGCellMap(ChangeType change_type, int3 if (detection_distance == -1) { RTLOG.error(Loc::current(), "The detection_distance is not initialize!"); } - for (NetShape& net_shape : getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : getNetDetailedShapeList(net_idx, *segment)) { PlanarRect real_rect = RTUTIL.getEnlargedRect(net_shape, detection_distance); if (!RTUTIL.hasRegularRect(real_rect, die.get_real_rect())) { continue; @@ -471,41 +472,101 @@ std::set DataManager::getViolationSet(EXTPlanarRect& region) #if 1 // 获得NetShapeList -std::vector DataManager::getNetShapeList(int32_t net_idx, std::vector>& segment_list) +std::vector DataManager::getNetGlobalShapeList(int32_t net_idx, std::vector>& segment_list) { std::vector net_shape_list; for (Segment& segment : segment_list) { - for (NetShape& net_shape : getNetShapeList(net_idx, segment)) { + for (NetShape& net_shape : getNetGlobalShapeList(net_idx, segment)) { net_shape_list.push_back(net_shape); } } return net_shape_list; } -std::vector DataManager::getNetShapeList(int32_t net_idx, Segment& segment) +std::vector DataManager::getNetGlobalShapeList(int32_t net_idx, Segment& segment) { std::vector net_shape_list; - for (NetShape& net_shape : getNetShapeList(net_idx, segment.get_first(), segment.get_second())) { + for (NetShape& net_shape : getNetGlobalShapeList(net_idx, segment.get_first(), segment.get_second())) { net_shape_list.push_back(net_shape); } return net_shape_list; } -std::vector DataManager::getNetShapeList(int32_t net_idx, MTree& coord_tree) +std::vector DataManager::getNetGlobalShapeList(int32_t net_idx, MTree& coord_tree) { std::vector net_shape_list; for (Segment*>& coord_segment : RTUTIL.getSegListByTree(coord_tree)) { - for (NetShape& net_shape : getNetShapeList(net_idx, coord_segment.get_first()->value(), coord_segment.get_second()->value())) { + for (NetShape& net_shape : getNetGlobalShapeList(net_idx, coord_segment.get_first()->value(), coord_segment.get_second()->value())) { net_shape_list.push_back(net_shape); } } return net_shape_list; } -std::vector DataManager::getNetShapeList(int32_t net_idx, LayerCoord& first_coord, LayerCoord& second_coord) +std::vector DataManager::getNetGlobalShapeList(int32_t net_idx, LayerCoord& first_coord, LayerCoord& second_coord) { - std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); - std::vector>& layer_via_master_list = RTDM.getDatabase().get_layer_via_master_list(); + ScaleAxis& gcell_axis = _database.get_gcell_axis(); + std::map>& routing_to_adjacent_cut_map = _database.get_routing_to_adjacent_cut_map(); + + PlanarRect first_gcell = RTUTIL.getRealRectByGCell(first_coord, gcell_axis); + int32_t first_layer_idx = first_coord.get_layer_idx(); + PlanarRect second_gcell = RTUTIL.getRealRectByGCell(second_coord, gcell_axis); + int32_t second_layer_idx = second_coord.get_layer_idx(); + + std::vector net_shape_list; + if (first_layer_idx != second_layer_idx) { + RTUTIL.swapByASC(first_layer_idx, second_layer_idx); + for (int32_t routing_layer_idx = first_layer_idx; routing_layer_idx < second_layer_idx; routing_layer_idx++) { + int32_t cut_layer_idx = -1; + { + std::vector& cut_layer_idx_list = routing_to_adjacent_cut_map[routing_layer_idx]; + cut_layer_idx = *std::max_element(cut_layer_idx_list.begin(), cut_layer_idx_list.end()); + } + LayerRect gcell_rect(first_gcell, cut_layer_idx); + net_shape_list.emplace_back(net_idx, gcell_rect, false); + } + } else { + LayerRect gcell_rect(RTUTIL.getBoundingBox({first_gcell, second_gcell}), first_layer_idx); + net_shape_list.emplace_back(net_idx, gcell_rect, true); + } + return net_shape_list; +} + +std::vector DataManager::getNetDetailedShapeList(int32_t net_idx, std::vector>& segment_list) +{ + std::vector net_shape_list; + for (Segment& segment : segment_list) { + for (NetShape& net_shape : getNetDetailedShapeList(net_idx, segment)) { + net_shape_list.push_back(net_shape); + } + } + return net_shape_list; +} + +std::vector DataManager::getNetDetailedShapeList(int32_t net_idx, Segment& segment) +{ + std::vector net_shape_list; + for (NetShape& net_shape : getNetDetailedShapeList(net_idx, segment.get_first(), segment.get_second())) { + net_shape_list.push_back(net_shape); + } + return net_shape_list; +} + +std::vector DataManager::getNetDetailedShapeList(int32_t net_idx, MTree& coord_tree) +{ + std::vector net_shape_list; + for (Segment*>& coord_segment : RTUTIL.getSegListByTree(coord_tree)) { + for (NetShape& net_shape : getNetDetailedShapeList(net_idx, coord_segment.get_first()->value(), coord_segment.get_second()->value())) { + net_shape_list.push_back(net_shape); + } + } + return net_shape_list; +} + +std::vector DataManager::getNetDetailedShapeList(int32_t net_idx, LayerCoord& first_coord, LayerCoord& second_coord) +{ + std::vector& routing_layer_list = _database.get_routing_layer_list(); + std::vector>& layer_via_master_list = _database.get_layer_via_master_list(); std::vector net_shape_list; int32_t first_layer_idx = first_coord.get_layer_idx(); @@ -587,6 +648,8 @@ void DataManager::buildConfig() if (_config.bottom_routing_layer_idx >= _config.top_routing_layer_idx) { RTLOG.error(Loc::current(), "The routing layer should be at least two layers!"); } + // ********** DataManager ********** // + _config.dm_temp_directory_path = _config.temp_directory_path + "data_manager/"; // ********** DRCEngine ********** // _config.de_temp_directory_path = _config.temp_directory_path + "drc_engine/"; // ********** GDSPlotter ********** // @@ -614,6 +677,8 @@ void DataManager::buildConfig() RTUTIL.removeDir(_config.temp_directory_path); RTUTIL.createDir(_config.temp_directory_path); RTUTIL.createDirByFile(_config.log_file_path); + // ********** DataManager ********** // + RTUTIL.createDir(_config.dm_temp_directory_path); // ********** DRCEngine ********** // RTUTIL.createDir(_config.de_temp_directory_path); // ********** GDSPlotter ********** // @@ -649,7 +714,6 @@ void DataManager::buildDatabase() buildLayerViaMasterList(); buildLayerViaMasterInfo(); buildObstacleList(); - buildNetInfo(); buildNetList(); buildDetectionDistance(); buildGCellMap(); @@ -1021,12 +1085,10 @@ void DataManager::makeLayerViaMasterList() for (ViaMaster& via_master : via_master_list) { // above LayerRect& above_enclosure = via_master.get_above_enclosure(); - Direction above_layer_direction = routing_layer_list[above_enclosure.get_layer_idx()].get_prefer_direction(); - via_master.set_above_direction(above_enclosure.getRectDirection(above_layer_direction)); + via_master.set_above_direction(above_enclosure.getRectDirection(Direction::kNone)); // below LayerRect& below_enclosure = via_master.get_below_enclosure(); - Direction below_layer_direction = routing_layer_list[below_enclosure.get_layer_idx()].get_prefer_direction(); - via_master.set_below_direction(below_enclosure.getRectDirection(below_layer_direction)); + via_master.set_below_direction(below_enclosure.getRectDirection(Direction::kNone)); } } std::vector direction_list; @@ -1042,7 +1104,7 @@ void DataManager::makeLayerViaMasterList() if (routing_shape.get_layer_idx() != 0) { continue; } - direction_num_map[routing_shape.get_real_rect().getRectDirection()]++; + direction_num_map[routing_shape.get_real_rect().getRectDirection(routing_layer_list[routing_shape.get_layer_idx()].get_prefer_direction())]++; } } } @@ -1195,19 +1257,6 @@ void DataManager::checkObstacleList() } } -void DataManager::buildNetInfo() -{ - Die& die = _database.get_die(); - std::map& block_shape_map = _database.get_block_shape_map(); - - for (auto& [block_name, shape] : block_shape_map) { - if (!RTUTIL.hasRegularRect(shape, die.get_real_rect())) { - RTLOG.error(Loc::current(), "This shape is outside the die!"); - } - shape = RTUTIL.getRegularRect(shape, die.get_real_rect()); - } -} - void DataManager::buildNetList() { Monitor monitor; @@ -1455,6 +1504,8 @@ void DataManager::printConfig() RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(2), _config.top_routing_layer); RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(1), "output_inter_result"); RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(2), _config.output_inter_result); + RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(1), "enable_notification"); + RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(2), _config.enable_notification); RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(1), "enable_timing"); RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(2), _config.enable_timing); RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(1), "enable_fast_mode"); @@ -1469,6 +1520,10 @@ void DataManager::printConfig() RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(2), _config.bottom_routing_layer_idx); RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(1), "top_routing_layer_idx"); RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(2), _config.top_routing_layer_idx); + // ********** DataManager ********** // + RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(1), "DataManager"); + RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(2), "dm_temp_directory_path"); + RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(3), _config.dm_temp_directory_path); // ********** DRCEngine ********** // RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(1), "DRCEngine"); RTLOG.info(Loc::current(), RTUTIL.getSpaceByTabNum(2), "de_temp_directory_path"); @@ -1632,11 +1687,11 @@ void DataManager::printDatabase() ///////////////////////////////////////////// } -void DataManager::writePYScript() +void DataManager::outputScript() { - std::string& temp_directory_path = RTDM.getConfig().temp_directory_path; + std::string& dm_temp_directory_path = _config.dm_temp_directory_path; - std::ofstream* python_file = RTUTIL.getOutputFileStream(RTUTIL.getString(temp_directory_path, "plot.py")); + std::ofstream* python_file = RTUTIL.getOutputFileStream(RTUTIL.getString(dm_temp_directory_path, "plot.py")); RTUTIL.pushStream(python_file, "import os", "\n"); RTUTIL.pushStream(python_file, "import pandas as pd", "\n"); RTUTIL.pushStream(python_file, "import matplotlib.pyplot as plt", "\n"); @@ -1661,6 +1716,65 @@ void DataManager::writePYScript() RTUTIL.closeFileStream(python_file); } +void DataManager::outputJson() +{ + int32_t enable_notification = _config.enable_notification; + if (!enable_notification) { + return; + } + std::map json_path_map; + json_path_map["env_map"] = outputEnvJson(); + RTI.sendNotification("DM", 1, json_path_map); +} + +std::string DataManager::outputEnvJson() +{ + Die& die = _database.get_die(); + std::vector& routing_layer_list = _database.get_routing_layer_list(); + std::vector& cut_layer_list = _database.get_cut_layer_list(); + std::vector& net_list = _database.get_net_list(); + std::string& dm_temp_directory_path = _config.dm_temp_directory_path; + + std::vector env_json_list; + { + nlohmann::json die_json; + die_json["die"] = {die.get_real_ll_x(), die.get_real_ll_y(), die.get_real_ur_x(), die.get_real_ur_y()}; + env_json_list.push_back(die_json); + } + { + nlohmann::json env_shape_json; + for (Obstacle& routing_obstacle : _database.get_routing_obstacle_list()) { + env_shape_json["env_shape"]["obs"]["shape"].push_back({routing_obstacle.get_real_ll_x(), routing_obstacle.get_real_ll_y(), + routing_obstacle.get_real_ur_x(), routing_obstacle.get_real_ur_y(), + routing_layer_list[routing_obstacle.get_layer_idx()].get_layer_name()}); + } + for (Obstacle& cut_obstacle : _database.get_cut_obstacle_list()) { + env_shape_json["env_shape"]["obs"]["shape"].push_back({cut_obstacle.get_real_ll_x(), cut_obstacle.get_real_ll_y(), cut_obstacle.get_real_ur_x(), + cut_obstacle.get_real_ur_y(), cut_layer_list[cut_obstacle.get_layer_idx()].get_layer_name()}); + } + for (Net& net : net_list) { + for (Pin& pin : net.get_pin_list()) { + for (EXTLayerRect& routing_shape : pin.get_routing_shape_list()) { + env_shape_json["env_shape"][net.get_net_name()]["shape"].push_back({routing_shape.get_real_ll_x(), routing_shape.get_real_ll_y(), + routing_shape.get_real_ur_x(), routing_shape.get_real_ur_y(), + routing_layer_list[routing_shape.get_layer_idx()].get_layer_name()}); + } + for (EXTLayerRect& cut_shape : pin.get_cut_shape_list()) { + env_shape_json["env_shape"][net.get_net_name()]["shape"].push_back({cut_shape.get_real_ll_x(), cut_shape.get_real_ll_y(), cut_shape.get_real_ur_x(), + cut_shape.get_real_ur_y(), + cut_layer_list[cut_shape.get_layer_idx()].get_layer_name()}); + } + } + } + env_json_list.push_back(env_shape_json); + } + std::string env_json_file_path = RTUTIL.getString(dm_temp_directory_path, "env_map.json"); + std::ofstream* env_json_file = RTUTIL.getOutputFileStream(env_json_file_path); + (*env_json_file) << env_json_list; + RTUTIL.closeFileStream(env_json_file); + return env_json_file_path; +} + #endif #if 1 // destroy diff --git a/src/operation/iRT/source/data_manager/DataManager.hpp b/src/operation/iRT/source/data_manager/DataManager.hpp index 18e37613675b1f323bb8d09b9604acd932421caa..21cd239d73a426de3eb6d04621911eaf7ea1faea 100644 --- a/src/operation/iRT/source/data_manager/DataManager.hpp +++ b/src/operation/iRT/source/data_manager/DataManager.hpp @@ -58,10 +58,14 @@ class DataManager #endif #if 1 // 获得NetShapeList - std::vector getNetShapeList(int32_t net_idx, std::vector>& segment_list); - std::vector getNetShapeList(int32_t net_idx, Segment& segment); - std::vector getNetShapeList(int32_t net_idx, MTree& coord_tree); - std::vector getNetShapeList(int32_t net_idx, LayerCoord& first_coord, LayerCoord& second_coord); + std::vector getNetGlobalShapeList(int32_t net_idx, std::vector>& segment_list); + std::vector getNetGlobalShapeList(int32_t net_idx, Segment& segment); + std::vector getNetGlobalShapeList(int32_t net_idx, MTree& coord_tree); + std::vector getNetGlobalShapeList(int32_t net_idx, LayerCoord& first_coord, LayerCoord& second_coord); + std::vector getNetDetailedShapeList(int32_t net_idx, std::vector>& segment_list); + std::vector getNetDetailedShapeList(int32_t net_idx, Segment& segment); + std::vector getNetDetailedShapeList(int32_t net_idx, MTree& coord_tree); + std::vector getNetDetailedShapeList(int32_t net_idx, LayerCoord& first_coord, LayerCoord& second_coord); #endif #if 1 // 获得唯一的pitch @@ -109,7 +113,6 @@ class DataManager void transObstacleList(); void makeObstacleList(); void checkObstacleList(); - void buildNetInfo(); void buildNetList(); void buildPinList(Net& net); void transPinList(Net& net); @@ -122,7 +125,9 @@ class DataManager int32_t getBucketIdx(int32_t scale_start, int32_t scale_end, int32_t bucket_start, int32_t bucket_end, int32_t bucket_length); void printConfig(); void printDatabase(); - void writePYScript(); + void outputScript(); + void outputJson(); + std::string outputEnvJson(); #endif #if 1 // destroy diff --git a/src/operation/iRT/source/data_manager/advance/Config.hpp b/src/operation/iRT/source/data_manager/advance/Config.hpp index 1fe37b12b5b90d18c300d575732437be8ed2892e..b101cd854548c0a6c50be64a2046010df934a782 100644 --- a/src/operation/iRT/source/data_manager/advance/Config.hpp +++ b/src/operation/iRT/source/data_manager/advance/Config.hpp @@ -32,6 +32,7 @@ class Config std::string bottom_routing_layer; // optional std::string top_routing_layer; // optional int32_t output_inter_result; // optional + int32_t enable_notification; // optional int32_t enable_timing; // optional int32_t enable_fast_mode; // optional int32_t enable_lsa; // optional @@ -40,6 +41,8 @@ class Config std::string log_file_path; // building int32_t bottom_routing_layer_idx; // building int32_t top_routing_layer_idx; // building + // ********** DataManager ********** // + std::string dm_temp_directory_path; // building // ********** DRCEngine ********** // std::string de_temp_directory_path; // building // ********** GDSPlotter ********** // diff --git a/src/operation/iRT/source/data_manager/advance/Database.hpp b/src/operation/iRT/source/data_manager/advance/Database.hpp index dbaf2b270ba52875a38c4fa131f37f2a0935bb0f..b08a95f8a74a89b0d073f04fe54744b51ab1fbd2 100644 --- a/src/operation/iRT/source/data_manager/advance/Database.hpp +++ b/src/operation/iRT/source/data_manager/advance/Database.hpp @@ -58,7 +58,6 @@ class Database std::map& get_layer_cut_shape_map() { return _layer_cut_shape_map; } std::vector& get_routing_obstacle_list() { return _routing_obstacle_list; } std::vector& get_cut_obstacle_list() { return _cut_obstacle_list; } - std::map& get_block_shape_map() { return _block_shape_map; } std::vector& get_net_list() { return _net_list; } GridMap& get_gcell_map() { return _gcell_map; } int32_t get_detection_distance() const { return _detection_distance; } @@ -94,7 +93,6 @@ class Database std::map _layer_cut_shape_map; std::vector _routing_obstacle_list; std::vector _cut_obstacle_list; - std::map _block_shape_map; std::vector _net_list; GridMap _gcell_map; int32_t _detection_distance = -1; diff --git a/src/operation/iRT/source/data_manager/advance/GCell.hpp b/src/operation/iRT/source/data_manager/advance/GCell.hpp index 01ee1b877cf2e97a9c0caf0c6d63a321574c1e92..573048333efe11c50610c86fa901ce3f931d804c 100644 --- a/src/operation/iRT/source/data_manager/advance/GCell.hpp +++ b/src/operation/iRT/source/data_manager/advance/GCell.hpp @@ -35,6 +35,7 @@ class GCell : public PlanarRect double get_internal_wire_unit() const { return _internal_wire_unit; } double get_internal_via_unit() const { return _internal_via_unit; } std::map>& get_routing_orient_supply_map() { return _routing_orient_supply_map; } + std::map>>& get_routing_ignore_net_orient_map() { return _routing_ignore_net_orient_map; } std::map*>>& get_net_global_result_map() { return _net_global_result_map; } std::map*>>& get_net_detailed_result_map() { return _net_detailed_result_map; } std::map>& get_net_detailed_patch_map() { return _net_detailed_patch_map; } @@ -60,6 +61,10 @@ class GCell : public PlanarRect { _routing_orient_supply_map = routing_orient_supply_map; } + void set_routing_ignore_net_orient_map(const std::map>>& routing_ignore_net_orient_map) + { + _routing_ignore_net_orient_map = routing_ignore_net_orient_map; + } void set_net_global_result_map(const std::map*>>& net_global_result_map) { _net_global_result_map = net_global_result_map; @@ -90,6 +95,8 @@ class GCell : public PlanarRect double _internal_via_unit = -1; // global supply std::map> _routing_orient_supply_map; + // global ignore net orient + std::map>> _routing_ignore_net_orient_map; // global routing result std::map*>> _net_global_result_map; // detailed routing result diff --git a/src/operation/iRT/source/data_manager/advance/Summary.hpp b/src/operation/iRT/source/data_manager/advance/Summary.hpp index e9df15dd631379265777f088dee269ef814eb170..b71b17763767115d6ebe6a87f71f543b51b3bb39 100644 --- a/src/operation/iRT/source/data_manager/advance/Summary.hpp +++ b/src/operation/iRT/source/data_manager/advance/Summary.hpp @@ -25,8 +25,6 @@ class PASummary public: PASummary() = default; ~PASummary() = default; - std::map routing_access_point_num_map; - int32_t total_access_point_num = 0; std::map routing_wire_length_map; double total_wire_length = 0; std::map cut_via_num_map; @@ -54,8 +52,8 @@ class TGSummary double total_demand = 0; double total_overflow = 0; double total_wire_length = 0; - std::map> clock_timing; - std::map power_map; + std::map> clock_timing_map; + std::map type_power_map; }; class LASummary @@ -71,8 +69,8 @@ class LASummary double total_wire_length = 0; std::map cut_via_num_map; int32_t total_via_num = 0; - std::map> clock_timing; - std::map power_map; + std::map> clock_timing_map; + std::map type_power_map; }; class SRSummary @@ -88,8 +86,8 @@ class SRSummary double total_wire_length = 0; std::map cut_via_num_map; int32_t total_via_num = 0; - std::map> clock_timing; - std::map power_map; + std::map> clock_timing_map; + std::map type_power_map; }; class TASummary @@ -116,8 +114,8 @@ class DRSummary int32_t total_patch_num = 0; std::map routing_violation_num_map; int32_t total_violation_num = 0; - std::map> clock_timing; - std::map power_map; + std::map> clock_timing_map; + std::map type_power_map; }; class VRSummary @@ -139,8 +137,8 @@ class VRSummary std::map among_net_violation_type_num_map; std::map among_net_routing_violation_num_map; int32_t among_net_total_violation_num = 0; - std::map> clock_timing; - std::map power_map; + std::map> clock_timing_map; + std::map type_power_map; }; class ERSummary @@ -156,8 +154,8 @@ class ERSummary double total_wire_length = 0; std::map cut_via_num_map; int32_t total_via_num = 0; - std::map> clock_timing; - std::map power_map; + std::map> clock_timing_map; + std::map type_power_map; }; class Summary diff --git a/src/operation/iRT/source/data_manager/advance/ViaMaster.hpp b/src/operation/iRT/source/data_manager/advance/ViaMaster.hpp index ad3f33d30a87d16f7e04b583951c786189796c88..2171a4e63e95e3fd8937d00e493d673c8cee6979 100644 --- a/src/operation/iRT/source/data_manager/advance/ViaMaster.hpp +++ b/src/operation/iRT/source/data_manager/advance/ViaMaster.hpp @@ -76,10 +76,10 @@ struct CmpViaMaster if (sort_status == SortStatus::kEqual) { Direction above_layer_direction = direction_list[a.get_above_enclosure().get_layer_idx()]; Direction below_layer_direction = direction_list[a.get_below_enclosure().get_layer_idx()]; - Direction a_above_direction = a.get_above_direction(); - Direction a_below_direction = a.get_below_direction(); - Direction b_above_direction = b.get_above_direction(); - Direction b_below_direction = b.get_below_direction(); + Direction a_above_direction = (a.get_above_direction() == Direction::kNone ? above_layer_direction : a.get_above_direction()); + Direction a_below_direction = (a.get_below_direction() == Direction::kNone ? below_layer_direction : a.get_below_direction()); + Direction b_above_direction = (b.get_above_direction() == Direction::kNone ? above_layer_direction : b.get_above_direction()); + Direction b_below_direction = (b.get_below_direction() == Direction::kNone ? below_layer_direction : b.get_below_direction()); if (a_above_direction == above_layer_direction && b_above_direction != above_layer_direction) { sort_status = SortStatus::kTrue; } else if (a_above_direction != above_layer_direction && b_above_direction == above_layer_direction) { diff --git a/src/operation/iRT/source/data_manager/advance/ViolationType.hpp b/src/operation/iRT/source/data_manager/advance/ViolationType.hpp index d6b3e5bdde6ef58ba8f974f5d3db20c9bb985342..7eb3994943766fcf6421a928c6455d996334e2a6 100644 --- a/src/operation/iRT/source/data_manager/advance/ViolationType.hpp +++ b/src/operation/iRT/source/data_manager/advance/ViolationType.hpp @@ -25,6 +25,7 @@ enum class ViolationType kNone, kAdjacentCutSpacing, kCornerFillSpacing, + kCornerSpacing, kCutEOLSpacing, kCutShort, kDifferentLayerCutSpacing, @@ -65,6 +66,9 @@ struct GetViolationTypeName case ViolationType::kCornerFillSpacing: violation_type_name = "corner_fill_spacing"; break; + case ViolationType::kCornerSpacing: + violation_type_name = "corner_spacing"; + break; case ViolationType::kCutEOLSpacing: violation_type_name = "cut_eol_spacing"; break; @@ -151,8 +155,8 @@ struct GetViolationTypeByName violation_type = ViolationType::kAdjacentCutSpacing; } else if (violation_type_name == "corner_fill_spacing") { violation_type = ViolationType::kCornerFillSpacing; - } else if (violation_type_name == "corner_fill_spacing") { - violation_type = ViolationType::kCornerFillSpacing; + } else if (violation_type_name == "corner_spacing") { + violation_type = ViolationType::kCornerSpacing; } else if (violation_type_name == "cut_eol_spacing") { violation_type = ViolationType::kCutEOLSpacing; } else if (violation_type_name == "cut_short") { diff --git a/src/operation/iRT/source/data_manager/basic/PlanarRect.hpp b/src/operation/iRT/source/data_manager/basic/PlanarRect.hpp index 4d1f55bfa56ffaacac6883ac712d81fcf7f9d486..c8c3ac4ba13be372e601f2fec61f49820f3da38a 100644 --- a/src/operation/iRT/source/data_manager/basic/PlanarRect.hpp +++ b/src/operation/iRT/source/data_manager/basic/PlanarRect.hpp @@ -96,7 +96,7 @@ inline int32_t PlanarRect::getWidth() const return std::min(getXSpan(), getYSpan()); } -inline Direction PlanarRect::getRectDirection(Direction point_direction = Direction::kNone) const +inline Direction PlanarRect::getRectDirection(Direction point_direction) const { Direction direction = Direction::kNone; diff --git a/src/operation/iRT/source/module/CMakeLists.txt b/src/operation/iRT/source/module/CMakeLists.txt index 8b12cca8b31029ea595fd9c3c0b22661f34fe1bd..15730db72f0e961024beabc7ebb930b76adb7638 100644 --- a/src/operation/iRT/source/module/CMakeLists.txt +++ b/src/operation/iRT/source/module/CMakeLists.txt @@ -12,17 +12,17 @@ add_subdirectory(${IRT_MODULE}/early_router) add_library(irt_module INTERFACE) -target_link_libraries(irt_module +target_link_libraries(irt_module INTERFACE - irt_drc_engine - irt_gds_plotter - irt_pin_accessor - irt_supply_analyzer - irt_topology_generator - irt_layer_assigner - irt_space_router - irt_track_assigner - irt_detailed_router - irt_violation_reporter - irt_early_router + irt_drc_engine + irt_gds_plotter + irt_pin_accessor + irt_supply_analyzer + irt_topology_generator + irt_layer_assigner + irt_space_router + irt_track_assigner + irt_detailed_router + irt_violation_reporter + irt_early_router ) diff --git a/src/operation/iRT/source/module/detailed_router/CMakeLists.txt b/src/operation/iRT/source/module/detailed_router/CMakeLists.txt index aa6435f74de7d02929fef8eedd0215ded57acc49..a2d7e7f0f4b06b0bb20493041cefc9399f71b471 100644 --- a/src/operation/iRT/source/module/detailed_router/CMakeLists.txt +++ b/src/operation/iRT/source/module/detailed_router/CMakeLists.txt @@ -2,8 +2,8 @@ if(DEBUG_IRT_DETAILED_ROUTER) message(STATUS "RT: DEBUG_IRT_DETAILED_ROUTER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_DETAILED_ROUTER") - set(CMAKE_BUILD_TYPE "Release") + message(STATUS "RT: RELEASE_IRT_DETAILED_ROUTER") + set(CMAKE_BUILD_TYPE "Release") endif() add_library(irt_detailed_router @@ -11,15 +11,15 @@ add_library(irt_detailed_router ${IRT_MODULE}/detailed_router/DetailedRouter.cpp ) -target_link_libraries(irt_detailed_router +target_link_libraries(irt_detailed_router PUBLIC - irt_data_manager - irt_module - irt_toolkit + irt_data_manager + irt_module + irt_toolkit ) -target_include_directories(irt_detailed_router +target_include_directories(irt_detailed_router PUBLIC - ${IRT_MODULE}/detailed_router/dr_data_manager - ${IRT_MODULE}/detailed_router + ${IRT_MODULE}/detailed_router/dr_data_manager + ${IRT_MODULE}/detailed_router ) diff --git a/src/operation/iRT/source/module/detailed_router/DetailedRouter.cpp b/src/operation/iRT/source/module/detailed_router/DetailedRouter.cpp index 86de71eed748b394cfee7a456ed9bfe5c60ee3d4..07b66f5dc49d49c4c4848d32c35dd4a16acdedd9 100644 --- a/src/operation/iRT/source/module/detailed_router/DetailedRouter.cpp +++ b/src/operation/iRT/source/module/detailed_router/DetailedRouter.cpp @@ -115,16 +115,12 @@ void DetailedRouter::routeDRModel(DRModel& dr_model) */ std::vector dr_iter_param_list; // clang-format off - dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 0, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); - dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 1, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); - dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 2, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); - dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 3, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); - dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 4, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); - dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 0, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); - dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 1, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); - dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 2, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); - dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 3, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); - dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 4, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); + dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 3, 0, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); + dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 3, 1, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); + dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 3, 2, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); + dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 3, 0, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); + dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 3, 1, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); + dr_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 3, 2, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 3, 10); // clang-format on initRoutingState(dr_model); for (int32_t i = 0, iter = 1; i < static_cast(dr_iter_param_list.size()); i++, iter++) { @@ -148,8 +144,7 @@ void DetailedRouter::routeDRModel(DRModel& dr_model) printSummary(dr_model); outputNetCSV(dr_model); outputViolationCSV(dr_model); - outputNetJson(dr_model); - outputViolationJson(dr_model); + outputJson(dr_model); RTLOG.info(Loc::current(), "***** End Iteration ", iter, "/", dr_iter_param_list.size(), "(", RTUTIL.getPercentage(iter, dr_iter_param_list.size()), ")", iter_monitor.getStatsInfo(), "*****"); if (stopIteration(dr_model)) { @@ -184,31 +179,53 @@ void DetailedRouter::setDRIterParam(DRModel& dr_model, int32_t iter, DRIterParam void DetailedRouter::initDRBoxMap(DRModel& dr_model) { ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); - - int32_t x_gcell_num = 0; - for (ScaleGrid& x_grid : gcell_axis.get_x_grid_list()) { - x_gcell_num += x_grid.get_step_num(); - } - int32_t y_gcell_num = 0; - for (ScaleGrid& y_grid : gcell_axis.get_y_grid_list()) { - y_gcell_num += y_grid.get_step_num(); - } - DRIterParam& dr_iter_param = dr_model.get_dr_iter_param(); + int32_t size = dr_iter_param.get_size(); int32_t offset = dr_iter_param.get_offset(); - int32_t x_box_num = static_cast(std::ceil((x_gcell_num - offset) / 1.0 / size)); - int32_t y_box_num = static_cast(std::ceil((y_gcell_num - offset) / 1.0 / size)); - + while (offset >= size) { + offset -= size; + } + std::vector x_scale_list; + { + int32_t x_gcell_num = 0; + for (ScaleGrid& x_grid : gcell_axis.get_x_grid_list()) { + x_gcell_num += x_grid.get_step_num(); + } + x_scale_list.push_back(0); + for (int32_t x_scale = offset; x_scale <= x_gcell_num; x_scale += size) { + x_scale_list.push_back(x_scale); + } + x_scale_list.push_back(x_gcell_num); + std::sort(x_scale_list.begin(), x_scale_list.end()); + x_scale_list.erase(std::unique(x_scale_list.begin(), x_scale_list.end()), x_scale_list.end()); + } + std::vector y_scale_list; + { + int32_t y_gcell_num = 0; + for (ScaleGrid& y_grid : gcell_axis.get_y_grid_list()) { + y_gcell_num += y_grid.get_step_num(); + } + y_scale_list.push_back(0); + for (int32_t y_scale = offset; y_scale <= y_gcell_num; y_scale += size) { + y_scale_list.push_back(y_scale); + } + y_scale_list.push_back(y_gcell_num); + std::sort(y_scale_list.begin(), y_scale_list.end()); + y_scale_list.erase(std::unique(y_scale_list.begin(), y_scale_list.end()), y_scale_list.end()); + } GridMap& dr_box_map = dr_model.get_dr_box_map(); - dr_box_map.init(x_box_num, y_box_num); - + { + int32_t x_box_num = static_cast(x_scale_list.size()) - 1; + int32_t y_box_num = static_cast(y_scale_list.size()) - 1; + dr_box_map.init(x_box_num, y_box_num); + } for (int32_t x = 0; x < dr_box_map.get_x_size(); x++) { for (int32_t y = 0; y < dr_box_map.get_y_size(); y++) { - int32_t grid_ll_x = std::max(offset + x * size, 0); - int32_t grid_ll_y = std::max(offset + y * size, 0); - int32_t grid_ur_x = std::min(offset + (x + 1) * size - 1, x_gcell_num - 1); - int32_t grid_ur_y = std::min(offset + (y + 1) * size - 1, y_gcell_num - 1); + int32_t grid_ll_x = x_scale_list[x]; + int32_t grid_ll_y = y_scale_list[y]; + int32_t grid_ur_x = x_scale_list[x + 1] - 1; + int32_t grid_ur_y = y_scale_list[y + 1] - 1; PlanarRect ll_gcell_rect = RTUTIL.getRealRectByGCell(PlanarCoord(grid_ll_x, grid_ll_y), gcell_axis); PlanarRect ur_gcell_rect = RTUTIL.getRealRectByGCell(PlanarCoord(grid_ur_x, grid_ur_y), gcell_axis); @@ -249,7 +266,9 @@ void DetailedRouter::buildBoxSchedule(DRModel& dr_model) dr_box_id_list.emplace_back(x, y); } } - dr_box_id_list_list.push_back(dr_box_id_list); + if (!dr_box_id_list.empty()) { + dr_box_id_list_list.push_back(dr_box_id_list); + } } } dr_model.set_dr_box_id_list_list(dr_box_id_list_list); @@ -264,7 +283,7 @@ void DetailedRouter::splitNetResult(DRModel& dr_model) ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { - std::vector*> del_segment_list; + std::set*> del_segment_set; std::vector> new_segment_list; for (Segment* segment : segment_set) { LayerCoord& first_coord = segment->get_first(); @@ -291,7 +310,7 @@ void DetailedRouter::splitNetResult(DRModel& dr_model) x_scale_list.push_back(x_scale); } x_scale_list.push_back(second_x); - del_segment_list.push_back(segment); + del_segment_set.insert(segment); for (size_t i = 1; i < x_scale_list.size(); i++) { new_segment_list.emplace_back(LayerCoord(x_scale_list[i - 1], first_coord.get_y(), first_coord.get_layer_idx()), LayerCoord(x_scale_list[i], first_coord.get_y(), first_coord.get_layer_idx())); @@ -315,14 +334,14 @@ void DetailedRouter::splitNetResult(DRModel& dr_model) y_scale_list.push_back(y_scale); } y_scale_list.push_back(second_y); - del_segment_list.push_back(segment); + del_segment_set.insert(segment); for (size_t i = 1; i < y_scale_list.size(); i++) { new_segment_list.emplace_back(LayerCoord(first_coord.get_x(), y_scale_list[i - 1], first_coord.get_layer_idx()), LayerCoord(first_coord.get_x(), y_scale_list[i], first_coord.get_layer_idx())); } } } - for (Segment* del_segment : del_segment_list) { + for (Segment* del_segment : del_segment_set) { RTDM.updateNetDetailedResultToGCellMap(ChangeType::kDel, net_idx, del_segment); } for (Segment& new_segment : new_segment_list) { @@ -578,6 +597,29 @@ void DetailedRouter::buildBoxTrackAxis(DRBox& dr_box) while (ur_y % manufacture_grid != 0) { ur_y--; } + std::map, std::set>>& layer_axis_map = dr_box.get_layer_axis_map(); + for (RoutingLayer& routing_layer : routing_layer_list) { + for (int32_t x_scale : RTUTIL.getScaleList(ll_x, ur_x, routing_layer.getXTrackGridList())) { + if (routing_layer.isPreferH()) + layer_axis_map[routing_layer.get_layer_idx()].first.insert(x_scale); + } + for (int32_t y_scale : RTUTIL.getScaleList(ll_y, ur_y, routing_layer.getYTrackGridList())) { + if (!routing_layer.isPreferH()) + layer_axis_map[routing_layer.get_layer_idx()].second.insert(y_scale); + } + } + for (DRTask* dr_task : dr_box.get_dr_task_list()) { + for (DRGroup& dr_group : dr_task->get_dr_group_list()) { + for (LayerCoord& coord : dr_group.get_coord_list()) { + int32_t layer_idx = coord.get_layer_idx(); + if (routing_layer_list[layer_idx].isPreferH()) { + layer_axis_map[layer_idx].first.insert(coord.get_x()); + } else { + layer_axis_map[layer_idx].second.insert(coord.get_y()); + } + } + } + } for (RoutingLayer& routing_layer : routing_layer_list) { for (int32_t x_scale : RTUTIL.getScaleList(ll_x, ur_x, routing_layer.getXTrackGridList())) { x_scale_list.push_back(x_scale); @@ -643,6 +685,7 @@ void DetailedRouter::buildDRNodeNeighbor(DRBox& dr_box) int32_t top_routing_layer_idx = RTDM.getConfig().top_routing_layer_idx; std::vector>& layer_node_map = dr_box.get_layer_node_map(); + std::map, std::set>>& layer_axis_map = dr_box.get_layer_axis_map(); for (int32_t layer_idx = 0; layer_idx < static_cast(layer_node_map.size()); layer_idx++) { bool routing_hv = true; if (layer_idx < bottom_routing_layer_idx || top_routing_layer_idx < layer_idx) { @@ -652,18 +695,66 @@ void DetailedRouter::buildDRNodeNeighbor(DRBox& dr_box) for (int32_t x = 0; x < dr_node_map.get_x_size(); x++) { for (int32_t y = 0; y < dr_node_map.get_y_size(); y++) { std::map& neighbor_node_map = dr_node_map[x][y].get_neighbor_node_map(); - if (routing_hv) { - if (x != 0) { - neighbor_node_map[Orientation::kWest] = &dr_node_map[x - 1][y]; + std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); + std::set neighbor_layer_x_axis_set; + std::set neighbor_layer_y_axis_set; + if (layer_idx != 0) { + for (int32_t x_scale : layer_axis_map[layer_idx - 1].first) { + neighbor_layer_x_axis_set.insert(x_scale); } - if (x != (dr_node_map.get_x_size() - 1)) { - neighbor_node_map[Orientation::kEast] = &dr_node_map[x + 1][y]; + for (int32_t y_scale : layer_axis_map[layer_idx - 1].second) { + neighbor_layer_y_axis_set.insert(y_scale); } - if (y != 0) { - neighbor_node_map[Orientation::kSouth] = &dr_node_map[x][y - 1]; + } + if (layer_idx != static_cast(layer_node_map.size()) - 1) { + for (int32_t x_scale : layer_axis_map[layer_idx + 1].first) { + neighbor_layer_x_axis_set.insert(x_scale); } - if (y != (dr_node_map.get_y_size() - 1)) { - neighbor_node_map[Orientation::kNorth] = &dr_node_map[x][y + 1]; + for (int32_t y_scale : layer_axis_map[layer_idx + 1].second) { + neighbor_layer_y_axis_set.insert(y_scale); + } + } + std::set curr_axis; + if (routing_layer_list[layer_idx].isPreferH()) { + curr_axis = layer_axis_map[layer_idx].first; + } else { + curr_axis = layer_axis_map[layer_idx].second; + } + if (routing_hv) { + if (!routing_layer_list[layer_idx].isPreferH()) { + if (RTUTIL.exist(curr_axis, dr_node_map[x][y].get_y())) { + if (x != 0) { + neighbor_node_map[Orientation::kWest] = &dr_node_map[x - 1][y]; + } + if (x != (dr_node_map.get_x_size() - 1)) { + neighbor_node_map[Orientation::kEast] = &dr_node_map[x + 1][y]; + } + } + if (RTUTIL.exist(neighbor_layer_x_axis_set, dr_node_map[x][y].get_x())) { + if (y != 0) { + neighbor_node_map[Orientation::kSouth] = &dr_node_map[x][y - 1]; + } + if (y != (dr_node_map.get_y_size() - 1)) { + neighbor_node_map[Orientation::kNorth] = &dr_node_map[x][y + 1]; + } + } + } else if (routing_layer_list[layer_idx].isPreferH()) { + if (RTUTIL.exist(curr_axis, dr_node_map[x][y].get_x())) { + if (y != 0) { + neighbor_node_map[Orientation::kSouth] = &dr_node_map[x][y - 1]; + } + if (y != (dr_node_map.get_y_size() - 1)) { + neighbor_node_map[Orientation::kNorth] = &dr_node_map[x][y + 1]; + } + } + if (RTUTIL.exist(neighbor_layer_y_axis_set, dr_node_map[x][y].get_y())) { + if (x != 0) { + neighbor_node_map[Orientation::kWest] = &dr_node_map[x - 1][y]; + } + if (x != (dr_node_map.get_x_size() - 1)) { + neighbor_node_map[Orientation::kEast] = &dr_node_map[x + 1][y]; + } + } } } if (layer_idx != 0) { @@ -1286,11 +1377,12 @@ void DetailedRouter::initSinglePatchTask(DRBox& dr_box, DRTask* dr_task) // single task dr_box.set_curr_patch_task(dr_task); dr_box.get_routing_patch_list().clear(); - dr_box.set_patch_violation_list(getPatchViolationList(dr_box)); + dr_box.set_patch_violation_list(getPatchViolationList(dr_box, {ViolationType::kMinimumArea}, {})); dr_box.get_tried_fix_violation_set().clear(); } -std::vector DetailedRouter::getPatchViolationList(DRBox& dr_box) +std::vector DetailedRouter::getPatchViolationList(DRBox& dr_box, const std::set& check_type_set, + const std::vector& check_region_list) { std::string top_name = RTUTIL.getString("dr_box_", dr_box.get_dr_box_id().get_x(), "_", dr_box.get_dr_box_id().get_y()); std::vector> env_shape_list; @@ -1352,6 +1444,8 @@ std::vector DetailedRouter::getPatchViolationList(DRBox& dr_box) de_task.set_net_result_map(net_result_map); de_task.set_net_patch_map(net_patch_map); de_task.set_need_checked_net_set(need_checked_net_set); + de_task.set_check_type_set(check_type_set); + de_task.set_check_region_list(check_region_list); return RTDE.getViolationList(de_task); } @@ -1406,7 +1500,7 @@ std::vector DetailedRouter::getViolationOverlapRect(DRBox& dr_box, V } } for (Segment* segment : dr_box.get_net_detailed_result_map()[curr_net_idx]) { - for (NetShape& net_shape : RTDM.getNetShapeList(curr_net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(curr_net_idx, *segment)) { if (!net_shape.get_is_routing()) { continue; } @@ -1416,7 +1510,7 @@ std::vector DetailedRouter::getViolationOverlapRect(DRBox& dr_box, V } } for (Segment& segment : dr_box.get_net_task_detailed_result_map()[curr_net_idx]) { - for (NetShape& net_shape : RTDM.getNetShapeList(curr_net_idx, segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(curr_net_idx, segment)) { if (!net_shape.get_is_routing()) { continue; } @@ -1467,19 +1561,35 @@ void DetailedRouter::addViolationToShadow(DRBox& dr_box) void DetailedRouter::patchSingleViolation(DRBox& dr_box) { + std::vector& routing_patch_list = dr_box.get_routing_patch_list(); + std::set& tried_fix_violation_set = dr_box.get_tried_fix_violation_set(); + LayerRect violation_rect = dr_box.get_curr_patch_violation().get_violation_shape().getRealLayerRect(); + std::vector dr_patch_list = getCandidatePatchList(dr_box); - for (DRPatch& dr_patch : dr_patch_list) { - buildSingleViolation(dr_box, dr_patch); - if (dr_box.get_curr_is_solved()) { - updateSingleViolation(dr_box); - break; + if (dr_patch_list.size() == 1) { + routing_patch_list.push_back(dr_patch_list.front().get_patch()); + } else if (dr_patch_list.size() >= 2) { + std::vector origin_patch_violation_list = getPatchViolationList(dr_box, {}, {violation_rect}); + + bool curr_is_solved = false; + for (DRPatch& dr_patch : dr_patch_list) { + std::vector curr_patch_violation_list; + { + routing_patch_list.push_back(dr_patch.get_patch()); + curr_patch_violation_list = getPatchViolationList(dr_box, {}, {violation_rect}); + routing_patch_list.pop_back(); + } + curr_is_solved = getSolvedStatus(dr_box, origin_patch_violation_list, curr_patch_violation_list); + if (curr_is_solved) { + routing_patch_list.push_back(dr_patch.get_patch()); + break; + } + } + if (!curr_is_solved) { + routing_patch_list.push_back(dr_patch_list.front().get_patch()); } } - if (!dr_patch_list.empty() && !dr_box.get_curr_is_solved()) { - buildSingleViolation(dr_box, dr_patch_list.front()); - updateSingleViolation(dr_box); - } - updateTriedFixViolation(dr_box); + tried_fix_violation_set.insert(dr_box.get_curr_patch_violation()); } std::vector DetailedRouter::getCandidatePatchList(DRBox& dr_box) @@ -1611,67 +1721,56 @@ std::vector DetailedRouter::getCandidatePatchList(DRBox& dr_box) return candidate_patch_list; } -void DetailedRouter::buildSingleViolation(DRBox& dr_box, DRPatch& dr_patch) +bool DetailedRouter::getSolvedStatus(DRBox& dr_box, std::vector& origin_patch_violation_list, std::vector& curr_patch_violation_list) { - { - dr_box.set_curr_candidate_patch(dr_patch); - } - { - dr_box.get_routing_patch_list().push_back(dr_patch.get_patch()); - dr_box.set_curr_patch_violation_list(getPatchViolationList(dr_box)); - dr_box.get_routing_patch_list().pop_back(); + std::map> env_type_origin_curr_map; + std::map> valid_type_origin_curr_map; + std::map> within_net_map; + for (Violation& origin_violation : origin_patch_violation_list) { + if (!isValidPatchViolation(dr_box, origin_violation)) { + env_type_origin_curr_map[origin_violation.get_violation_type()].first++; + } else { + valid_type_origin_curr_map[origin_violation.get_violation_type()].first++; + } + if (origin_violation.get_violation_net_set().size() > 1) { + within_net_map[origin_violation.get_violation_type()].first++; + } } - { - std::map> env_type_origin_curr_map; - std::map> valid_type_origin_curr_map; - for (Violation& origin_violation : dr_box.get_patch_violation_list()) { - if (!isValidPatchViolation(dr_box, origin_violation)) { - env_type_origin_curr_map[origin_violation.get_violation_type()].first++; - } else { - valid_type_origin_curr_map[origin_violation.get_violation_type()].first++; - } + for (Violation& curr_violation : curr_patch_violation_list) { + if (!isValidPatchViolation(dr_box, curr_violation)) { + env_type_origin_curr_map[curr_violation.get_violation_type()].second++; + } else { + valid_type_origin_curr_map[curr_violation.get_violation_type()].second++; } - for (Violation& curr_violation : dr_box.get_curr_patch_violation_list()) { - if (!isValidPatchViolation(dr_box, curr_violation)) { - env_type_origin_curr_map[curr_violation.get_violation_type()].second++; - } else { - valid_type_origin_curr_map[curr_violation.get_violation_type()].second++; - } + if (curr_violation.get_violation_net_set().size() > 1) { + within_net_map[curr_violation.get_violation_type()].second++; } - bool is_solved = true; - for (auto& [violation_type, origin_curr] : env_type_origin_curr_map) { - if (!is_solved) { - break; - } - is_solved = origin_curr.second <= origin_curr.first; + } + bool curr_is_solved = true; + for (auto& [violation_type, origin_curr] : env_type_origin_curr_map) { + if (!curr_is_solved) { + break; } - for (auto& [violation_type, origin_curr] : valid_type_origin_curr_map) { - if (!is_solved) { - break; - } - is_solved = origin_curr.second < origin_curr.first; + curr_is_solved = origin_curr.second <= origin_curr.first; + } + for (auto& [violation_type, origin_curr] : valid_type_origin_curr_map) { + if (!curr_is_solved) { + break; } - dr_box.set_curr_is_solved(is_solved); + curr_is_solved = origin_curr.second < origin_curr.first; } -} - -void DetailedRouter::updateSingleViolation(DRBox& dr_box) -{ - dr_box.get_routing_patch_list().push_back(dr_box.get_curr_candidate_patch().get_patch()); - dr_box.set_patch_violation_list(dr_box.get_curr_patch_violation_list()); -} - -void DetailedRouter::updateTriedFixViolation(DRBox& dr_box) -{ - dr_box.get_tried_fix_violation_set().insert(dr_box.get_curr_patch_violation()); + for (auto& [violation_type, origin_curr] : within_net_map) { + if (!curr_is_solved) { + break; + } + curr_is_solved = origin_curr.second <= origin_curr.first; + } + return curr_is_solved; } void DetailedRouter::resetSingleViolation(DRBox& dr_box) { dr_box.set_curr_patch_violation(Violation()); - dr_box.set_curr_candidate_patch(DRPatch()); - dr_box.get_curr_patch_violation_list().clear(); - dr_box.set_curr_is_solved(false); } void DetailedRouter::clearViolationShadow(DRBox& dr_box) @@ -1928,7 +2027,7 @@ void DetailedRouter::uploadNetPatch(DRModel& dr_model) for (auto& [net_idx, patch_set] : net_detailed_patch_map) { std::map> layer_rect_map; for (Segment* segment : net_detailed_result_map[net_idx]) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { if (!net_shape.get_is_routing()) { continue; } @@ -2082,8 +2181,7 @@ void DetailedRouter::selectBestResult(DRModel& dr_model) printSummary(dr_model); outputNetCSV(dr_model); outputViolationCSV(dr_model); - outputNetJson(dr_model); - outputViolationJson(dr_model); + outputJson(dr_model); RTLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); } @@ -2153,7 +2251,7 @@ void DetailedRouter::updateFixedRectToGraph(DRBox& dr_box, ChangeType change_typ void DetailedRouter::updateFixedRectToGraph(DRBox& dr_box, ChangeType change_type, int32_t net_idx, Segment* segment) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { for (auto& [dr_node, orientation_set] : getNodeOrientationMap(dr_box, net_shape)) { for (Orientation orientation : orientation_set) { if (change_type == ChangeType::kAdd) { @@ -2182,7 +2280,7 @@ void DetailedRouter::updateRoutedRectToGraph(DRBox& dr_box, ChangeType change_ty void DetailedRouter::updateRoutedRectToGraph(DRBox& dr_box, ChangeType change_type, int32_t net_idx, Segment& segment) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, segment)) { for (auto& [dr_node, orientation_set] : getNodeOrientationMap(dr_box, net_shape)) { for (Orientation orientation : orientation_set) { if (change_type == ChangeType::kAdd) { @@ -2529,7 +2627,7 @@ void DetailedRouter::updateFixedRectToShadow(DRBox& dr_box, ChangeType change_ty void DetailedRouter::updateFixedRectToShadow(DRBox& dr_box, ChangeType change_type, int32_t net_idx, Segment* segment) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { if (!net_shape.get_is_routing()) { continue; } @@ -2562,7 +2660,7 @@ void DetailedRouter::updateRoutedRectToShadow(DRBox& dr_box, ChangeType change_t void DetailedRouter::updateRoutedRectToShadow(DRBox& dr_box, ChangeType change_type, int32_t net_idx, Segment& segment) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, segment)) { if (!net_shape.get_is_routing()) { continue; } @@ -2734,8 +2832,8 @@ void DetailedRouter::updateSummary(DRModel& dr_model) int32_t& total_patch_num = summary.iter_dr_summary_map[dr_model.get_iter()].total_patch_num; std::map& routing_violation_num_map = summary.iter_dr_summary_map[dr_model.get_iter()].routing_violation_num_map; int32_t& total_violation_num = summary.iter_dr_summary_map[dr_model.get_iter()].total_violation_num; - std::map>& clock_timing = summary.iter_dr_summary_map[dr_model.get_iter()].clock_timing; - std::map& power_map = summary.iter_dr_summary_map[dr_model.get_iter()].power_map; + std::map>& clock_timing_map = summary.iter_dr_summary_map[dr_model.get_iter()].clock_timing_map; + std::map& type_power_map = summary.iter_dr_summary_map[dr_model.get_iter()].type_power_map; std::vector& dr_net_list = dr_model.get_dr_net_list(); @@ -2747,8 +2845,8 @@ void DetailedRouter::updateSummary(DRModel& dr_model) total_patch_num = 0; routing_violation_num_map.clear(); total_violation_num = 0; - clock_timing.clear(); - power_map.clear(); + clock_timing_map.clear(); + type_power_map.clear(); for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { for (Segment* segment : segment_set) { @@ -2795,7 +2893,7 @@ void DetailedRouter::updateSummary(DRModel& dr_model) routing_segment_list_list[net_idx].emplace_back(segment->get_first(), segment->get_second()); } } - RTI.updateTimingAndPower(real_pin_coord_map_list, routing_segment_list_list, clock_timing, power_map); + RTI.updateTimingAndPower(real_pin_coord_map_list, routing_segment_list_list, clock_timing_map, type_power_map); } } @@ -2814,8 +2912,8 @@ void DetailedRouter::printSummary(DRModel& dr_model) int32_t& total_patch_num = summary.iter_dr_summary_map[dr_model.get_iter()].total_patch_num; std::map& routing_violation_num_map = summary.iter_dr_summary_map[dr_model.get_iter()].routing_violation_num_map; int32_t& total_violation_num = summary.iter_dr_summary_map[dr_model.get_iter()].total_violation_num; - std::map>& clock_timing = summary.iter_dr_summary_map[dr_model.get_iter()].clock_timing; - std::map& power_map = summary.iter_dr_summary_map[dr_model.get_iter()].power_map; + std::map>& clock_timing_map = summary.iter_dr_summary_map[dr_model.get_iter()].clock_timing_map; + std::map& type_power_map = summary.iter_dr_summary_map[dr_model.get_iter()].type_power_map; fort::char_table routing_wire_length_map_table; { @@ -2875,16 +2973,16 @@ void DetailedRouter::printSummary(DRModel& dr_model) << "tns" << "wns" << "freq" << fort::endr; - for (auto& [clock_name, timing_map] : clock_timing) { + for (auto& [clock_name, timing_map] : clock_timing_map) { timing_table << clock_name << timing_map["TNS"] << timing_map["WNS"] << timing_map["Freq(MHz)"] << fort::endr; } power_table << fort::header << "power_type"; - for (auto& [type, power] : power_map) { + for (auto& [type, power] : type_power_map) { power_table << fort::header << type; } power_table << fort::endr; power_table << "power_value"; - for (auto& [type, power] : power_map) { + for (auto& [type, power] : type_power_map) { power_table << power; } power_table << fort::endr; @@ -2982,58 +3080,68 @@ void DetailedRouter::outputViolationCSV(DRModel& dr_model) } } -void DetailedRouter::outputNetJson(DRModel& dr_model) +void DetailedRouter::outputJson(DRModel& dr_model) +{ + int32_t enable_notification = RTDM.getConfig().enable_notification; + if (!enable_notification) { + return; + } + std::map json_path_map; + json_path_map["net_map"] = outputNetJson(dr_model); + json_path_map["violation_map"] = outputViolationJson(dr_model); + json_path_map["summary"] = outputSummaryJson(dr_model); + RTI.sendNotification("DR", dr_model.get_iter(), json_path_map); +} + +std::string DetailedRouter::outputNetJson(DRModel& dr_model) { Die& die = RTDM.getDatabase().get_die(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); std::vector& net_list = RTDM.getDatabase().get_net_list(); std::string& dr_temp_directory_path = RTDM.getConfig().dr_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector net_json_list; - net_json_list.resize(net_list.size()); - for (Net& net : net_list) { - net_json_list[net.get_net_idx()]["net_name"] = net.get_net_name(); - } - for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { - for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { - std::string layer_name; - if (net_shape.get_is_routing()) { - layer_name = routing_layer_list[net_shape.get_layer_idx()].get_layer_name(); - } else { - layer_name = cut_layer_list[net_shape.get_layer_idx()].get_layer_name(); + { + nlohmann::json result_shape_json; + for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { + std::string net_name = net_list[net_idx].get_net_name(); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { + std::string layer_name; + if (net_shape.get_is_routing()) { + layer_name = routing_layer_list[net_shape.get_layer_idx()].get_layer_name(); + } else { + layer_name = cut_layer_list[net_shape.get_layer_idx()].get_layer_name(); + } + result_shape_json["result_shape"][net_name]["path"].push_back( + {net_shape.get_ll_x(), net_shape.get_ll_y(), net_shape.get_ur_x(), net_shape.get_ur_y(), layer_name}); } - net_json_list[net_idx]["result"].push_back({net_shape.get_ll_x(), net_shape.get_ll_y(), net_shape.get_ur_x(), net_shape.get_ur_y(), layer_name}); } } - } - for (auto& [net_idx, patch_set] : RTDM.getNetDetailedPatchMap(die)) { - for (EXTLayerRect* patch : patch_set) { - net_json_list[net_idx]["patch"].push_back({patch->get_real_ll_x(), patch->get_real_ll_y(), patch->get_real_ur_x(), patch->get_real_ur_y(), - routing_layer_list[patch->get_layer_idx()].get_layer_name()}); + for (auto& [net_idx, patch_set] : RTDM.getNetDetailedPatchMap(die)) { + std::string net_name = net_list[net_idx].get_net_name(); + for (EXTLayerRect* patch : patch_set) { + result_shape_json["result_shape"][net_name]["patch"].push_back({patch->get_real_ll_x(), patch->get_real_ll_y(), patch->get_real_ur_x(), + patch->get_real_ur_y(), routing_layer_list[patch->get_layer_idx()].get_layer_name()}); + } } + net_json_list.push_back(result_shape_json); } std::string net_json_file_path = RTUTIL.getString(dr_temp_directory_path, "net_map_", dr_model.get_iter(), ".json"); std::ofstream* net_json_file = RTUTIL.getOutputFileStream(net_json_file_path); (*net_json_file) << net_json_list; RTUTIL.closeFileStream(net_json_file); - RTI.sendNotification(RTUTIL.getString("DR_", dr_model.get_iter(), "_net_map"), net_json_file_path); + return net_json_file_path; } -void DetailedRouter::outputViolationJson(DRModel& dr_model) +std::string DetailedRouter::outputViolationJson(DRModel& dr_model) { Die& die = RTDM.getDatabase().get_die(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& net_list = RTDM.getDatabase().get_net_list(); std::string& dr_temp_directory_path = RTDM.getConfig().dr_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector violation_json_list; for (Violation* violation : RTDM.getViolationSet(die)) { EXTLayerRect& violation_shape = violation->get_violation_shape(); @@ -3044,7 +3152,11 @@ void DetailedRouter::outputViolationJson(DRModel& dr_model) = {violation_shape.get_real_rect().get_ll_x(), violation_shape.get_real_rect().get_ll_y(), violation_shape.get_real_rect().get_ur_x(), violation_shape.get_real_rect().get_ur_y(), routing_layer_list[violation_shape.get_layer_idx()].get_layer_name()}; for (int32_t net_idx : violation->get_violation_net_set()) { - violation_json["net"].push_back(net_list[net_idx].get_net_name()); + if (net_idx != -1) { + violation_json["net"].push_back(net_list[net_idx].get_net_name()); + } else { + violation_json["net"].push_back("obs"); + } } violation_json_list.push_back(violation_json); } @@ -3052,7 +3164,59 @@ void DetailedRouter::outputViolationJson(DRModel& dr_model) std::ofstream* violation_json_file = RTUTIL.getOutputFileStream(violation_json_file_path); (*violation_json_file) << violation_json_list; RTUTIL.closeFileStream(violation_json_file); - RTI.sendNotification(RTUTIL.getString("DR_", dr_model.get_iter(), "_violation_map"), violation_json_file_path); + return violation_json_file_path; +} + +std::string DetailedRouter::outputSummaryJson(DRModel& dr_model) +{ + std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); + std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); + Summary& summary = RTDM.getDatabase().get_summary(); + std::string& dr_temp_directory_path = RTDM.getConfig().dr_temp_directory_path; + + std::map& routing_wire_length_map = summary.iter_dr_summary_map[dr_model.get_iter()].routing_wire_length_map; + double& total_wire_length = summary.iter_dr_summary_map[dr_model.get_iter()].total_wire_length; + std::map& cut_via_num_map = summary.iter_dr_summary_map[dr_model.get_iter()].cut_via_num_map; + int32_t& total_via_num = summary.iter_dr_summary_map[dr_model.get_iter()].total_via_num; + std::map& routing_patch_num_map = summary.iter_dr_summary_map[dr_model.get_iter()].routing_patch_num_map; + int32_t& total_patch_num = summary.iter_dr_summary_map[dr_model.get_iter()].total_patch_num; + std::map& routing_violation_num_map = summary.iter_dr_summary_map[dr_model.get_iter()].routing_violation_num_map; + int32_t& total_violation_num = summary.iter_dr_summary_map[dr_model.get_iter()].total_violation_num; + std::map>& clock_timing_map = summary.iter_dr_summary_map[dr_model.get_iter()].clock_timing_map; + std::map& type_power_map = summary.iter_dr_summary_map[dr_model.get_iter()].type_power_map; + + nlohmann::json summary_json; + summary_json["iter"] = dr_model.get_iter(); + for (auto& [routing_layer_idx, wire_length] : routing_wire_length_map) { + summary_json["routing_wire_length_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = wire_length; + } + summary_json["total_wire_length"] = total_wire_length; + for (auto& [cut_layer_idx, via_num] : cut_via_num_map) { + summary_json["cut_via_num_map"][cut_layer_list[cut_layer_idx].get_layer_name()] = via_num; + } + summary_json["total_via_num"] = total_via_num; + for (auto& [routing_layer_idx, patch_num] : routing_patch_num_map) { + summary_json["routing_patch_num_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = patch_num; + } + summary_json["total_patch_num"] = total_patch_num; + for (auto& [routing_layer_idx, violation_num] : routing_violation_num_map) { + summary_json["routing_violation_num_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = violation_num; + } + summary_json["total_violation_num"] = total_violation_num; + for (auto& [clock_name, timing] : clock_timing_map) { + summary_json["clock_timing_map"]["clock_name"] = clock_name; + summary_json["clock_timing_map"]["timing"] = timing; + } + for (auto& [type, power] : type_power_map) { + summary_json["type_power_map"]["type"] = type; + summary_json["type_power_map"]["power"] = power; + } + + std::string summary_json_file_path = RTUTIL.getString(dr_temp_directory_path, "summary_", dr_model.get_iter(), ".json"); + std::ofstream* summary_json_file = RTUTIL.getOutputFileStream(summary_json_file_path); + (*summary_json_file) << summary_json; + RTUTIL.closeFileStream(summary_json_file); + return summary_json_file_path; } #endif @@ -3070,6 +3234,17 @@ void DetailedRouter::debugPlotDRModel(DRModel& dr_model, std::string flag) GPGDS gp_gds; + // base_region + { + GPStruct base_region_struct("base_region"); + GPBoundary gp_boundary; + gp_boundary.set_layer_idx(0); + gp_boundary.set_data_type(0); + gp_boundary.set_rect(die.get_real_rect()); + base_region_struct.push(gp_boundary); + gp_gds.addStruct(base_region_struct); + } + // gcell_axis { GPStruct gcell_axis_struct("gcell_axis"); @@ -3153,13 +3328,32 @@ void DetailedRouter::debugPlotDRModel(DRModel& dr_model, std::string flag) gp_gds.addStruct(access_point_struct); } + // routing result + for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { + GPStruct global_result_struct(RTUTIL.getString("global_result(net_", net_idx, ")")); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetGlobalShapeList(net_idx, *segment)) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kGlobalPath)); + gp_boundary.set_rect(net_shape.get_rect()); + if (net_shape.get_is_routing()) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(net_shape.get_layer_idx())); + } + global_result_struct.push(gp_boundary); + } + } + gp_gds.addStruct(global_result_struct); + } + // routing result for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { GPStruct detailed_result_struct(RTUTIL.getString("detailed_result(net_", net_idx, ")")); for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { GPBoundary gp_boundary; - gp_boundary.set_data_type(static_cast(GPDataType::kPath)); + gp_boundary.set_data_type(static_cast(GPDataType::kDetailedPath)); gp_boundary.set_rect(net_shape.get_rect()); if (net_shape.get_is_routing()) { gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); @@ -3384,7 +3578,7 @@ void DetailedRouter::debugPlotDRBox(DRBox& dr_box, std::string flag) for (auto& [net_idx, segment_set] : dr_box.get_net_detailed_result_map()) { GPStruct detailed_result_struct(RTUTIL.getString("detailed_result(net_", net_idx, ")")); for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { GPBoundary gp_boundary; gp_boundary.set_data_type(static_cast(GPDataType::kShape)); gp_boundary.set_rect(net_shape.get_rect()); @@ -3667,9 +3861,9 @@ void DetailedRouter::debugPlotDRBox(DRBox& dr_box, std::string flag) task_struct.push(gp_boundary); } for (Segment& segment : dr_box.get_net_task_detailed_result_map()[dr_task->get_net_idx()]) { - for (NetShape& net_shape : RTDM.getNetShapeList(dr_task->get_net_idx(), segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(dr_task->get_net_idx(), segment)) { GPBoundary gp_boundary; - gp_boundary.set_data_type(static_cast(GPDataType::kPath)); + gp_boundary.set_data_type(static_cast(GPDataType::kDetailedPath)); gp_boundary.set_rect(net_shape.get_rect()); if (net_shape.get_is_routing()) { gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); diff --git a/src/operation/iRT/source/module/detailed_router/DetailedRouter.hpp b/src/operation/iRT/source/module/detailed_router/DetailedRouter.hpp index ac0f2c56fcd1b9a1a23bae94b9cd5400361cd2f0..5b4c218e8a5f7c2f6d913b8ddd2c7bb56126c8f2 100644 --- a/src/operation/iRT/source/module/detailed_router/DetailedRouter.hpp +++ b/src/operation/iRT/source/module/detailed_router/DetailedRouter.hpp @@ -109,16 +109,14 @@ class DetailedRouter double getEstimateViaCost(DRBox& dr_box, DRNode* start_node, DRNode* end_node); void patchDRTask(DRBox& dr_box, DRTask* dr_task); void initSinglePatchTask(DRBox& dr_box, DRTask* dr_task); - std::vector getPatchViolationList(DRBox& dr_box); + std::vector getPatchViolationList(DRBox& dr_box, const std::set& check_type_set, const std::vector& check_region_list); bool searchViolation(DRBox& dr_box); bool isValidPatchViolation(DRBox& dr_box, Violation& violation); std::vector getViolationOverlapRect(DRBox& dr_box, Violation& violation); void addViolationToShadow(DRBox& dr_box); void patchSingleViolation(DRBox& dr_box); std::vector getCandidatePatchList(DRBox& dr_box); - void buildSingleViolation(DRBox& dr_box, DRPatch& dr_patch); - void updateSingleViolation(DRBox& dr_box); - void updateTriedFixViolation(DRBox& dr_box); + bool getSolvedStatus(DRBox& dr_box, std::vector& origin_patch_violation_list, std::vector& curr_patch_violation_list); void resetSingleViolation(DRBox& dr_box); void clearViolationShadow(DRBox& dr_box); void updateTaskPatch(DRBox& dr_box); @@ -174,8 +172,10 @@ class DetailedRouter void printSummary(DRModel& dr_model); void outputNetCSV(DRModel& dr_model); void outputViolationCSV(DRModel& dr_model); - void outputNetJson(DRModel& dr_model); - void outputViolationJson(DRModel& dr_model); + void outputJson(DRModel& dr_model); + std::string outputNetJson(DRModel& dr_model); + std::string outputViolationJson(DRModel& dr_model); + std::string outputSummaryJson(DRModel& dr_model); #endif #if 1 // debug diff --git a/src/operation/iRT/source/module/detailed_router/dr_data_manager/DRBox.hpp b/src/operation/iRT/source/module/detailed_router/dr_data_manager/DRBox.hpp index 6808b8bd86730ab07dfc212b8bf7d9e176304a6e..2628e399414f7b01019f4c013e08272f5d5a1abd 100644 --- a/src/operation/iRT/source/module/detailed_router/dr_data_manager/DRBox.hpp +++ b/src/operation/iRT/source/module/detailed_router/dr_data_manager/DRBox.hpp @@ -52,9 +52,11 @@ class DRBox ScaleAxis& get_box_track_axis() { return _box_track_axis; } std::vector>& get_layer_node_map() { return _layer_node_map; } std::vector& get_layer_shadow_map() { return _layer_shadow_map; } + std::map, std::set>>& get_layer_axis_map() { return _layer_axis_map; } std::map>>& get_best_net_task_detailed_result_map() { return _best_net_task_detailed_result_map; } std::map>& get_best_net_task_detailed_patch_map() { return _best_net_task_detailed_patch_map; } std::vector& get_best_route_violation_list() { return _best_route_violation_list; } + // setter void set_box_rect(const EXTPlanarRect& box_rect) { _box_rect = box_rect; } void set_dr_box_id(const DRBoxId& dr_box_id) { _dr_box_id = dr_box_id; } @@ -86,6 +88,7 @@ class DRBox void set_box_track_axis(const ScaleAxis& box_track_axis) { _box_track_axis = box_track_axis; } void set_layer_node_map(const std::vector>& layer_node_map) { _layer_node_map = layer_node_map; } void set_layer_shadow_map(const std::vector& layer_shadow_map) { _layer_shadow_map = layer_shadow_map; } + void set_layer_axis_map(const std::map, std::set>>& layer_axis_map) { _layer_axis_map = layer_axis_map; } void set_best_net_task_detailed_result_map(const std::map>>& best_net_task_detailed_result_map) { _best_net_task_detailed_result_map = best_net_task_detailed_result_map; @@ -138,13 +141,7 @@ class DRBox void set_tried_fix_violation_set(const std::set& tried_fix_violation_set) { _tried_fix_violation_set = tried_fix_violation_set; } // single violation Violation& get_curr_patch_violation() { return _curr_patch_violation; } - DRPatch& get_curr_candidate_patch() { return _curr_candidate_patch; } - std::vector& get_curr_patch_violation_list() { return _curr_patch_violation_list; } - bool get_curr_is_solved() const { return _curr_is_solved; } void set_curr_patch_violation(const Violation& curr_patch_violation) { _curr_patch_violation = curr_patch_violation; } - void set_curr_candidate_patch(const DRPatch& curr_candidate_patch) { _curr_candidate_patch = curr_candidate_patch; } - void set_curr_patch_violation_list(const std::vector& curr_patch_violation_list) { _curr_patch_violation_list = curr_patch_violation_list; } - void set_curr_is_solved(const bool curr_is_solved) { _curr_is_solved = curr_is_solved; } #endif private: @@ -163,6 +160,7 @@ class DRBox ScaleAxis _box_track_axis; std::vector> _layer_node_map; std::vector _layer_shadow_map; + std::map, std::set>> _layer_axis_map; std::map>> _best_net_task_detailed_result_map; std::map> _best_net_task_detailed_patch_map; std::vector _best_route_violation_list; @@ -188,9 +186,6 @@ class DRBox std::set _tried_fix_violation_set; // single violation Violation _curr_patch_violation; - DRPatch _curr_candidate_patch; - std::vector _curr_patch_violation_list; - bool _curr_is_solved = false; #endif }; diff --git a/src/operation/iRT/source/module/drc_engine/CMakeLists.txt b/src/operation/iRT/source/module/drc_engine/CMakeLists.txt index e1df548accafb56edc4f02b6752221b171701b6a..1eab2505d0a8db92cb16a0f36dc96c36aa8fddf3 100644 --- a/src/operation/iRT/source/module/drc_engine/CMakeLists.txt +++ b/src/operation/iRT/source/module/drc_engine/CMakeLists.txt @@ -2,8 +2,8 @@ if(DEBUG_IRT_DRC_ENGINE) message(STATUS "RT: DEBUG_IRT_DRC_ENGINE") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_DRC_ENGINE") - set(CMAKE_BUILD_TYPE "Release") + message(STATUS "RT: RELEASE_IRT_DRC_ENGINE") + set(CMAKE_BUILD_TYPE "Release") endif() add_library(irt_drc_engine @@ -11,15 +11,15 @@ add_library(irt_drc_engine ${IRT_MODULE}/drc_engine/DRCEngine.cpp ) -target_link_libraries(irt_drc_engine +target_link_libraries(irt_drc_engine PUBLIC - irt_data_manager - irt_module - irt_toolkit + irt_data_manager + irt_module + irt_toolkit ) -target_include_directories(irt_drc_engine +target_include_directories(irt_drc_engine PUBLIC - ${IRT_MODULE}/drc_engine/de_data_manager - ${IRT_MODULE}/drc_engine + ${IRT_MODULE}/drc_engine/de_data_manager + ${IRT_MODULE}/drc_engine ) diff --git a/src/operation/iRT/source/module/drc_engine/DRCEngine.cpp b/src/operation/iRT/source/module/drc_engine/DRCEngine.cpp index 846ad30cb2a1081b54342ccdabf71f43301f0629..545afb939c396329114916d26735afd757735e2d 100644 --- a/src/operation/iRT/source/module/drc_engine/DRCEngine.cpp +++ b/src/operation/iRT/source/module/drc_engine/DRCEngine.cpp @@ -55,15 +55,16 @@ void DRCEngine::init() RTLOG.info(Loc::current(), "Starting..."); RTI.initIDRC(); - buildIgnoredViolationSet(); + if (!RTDM.getConfig().enable_fast_mode) { + buildIgnoredViolationSet(); + } RTLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); } std::vector DRCEngine::getViolationList(DETask& de_task) { - int32_t enable_fast_mode = RTDM.getConfig().enable_fast_mode; - if (enable_fast_mode) { + if (RTDM.getConfig().enable_fast_mode) { return {}; } getViolationListByInterface(de_task); @@ -147,8 +148,8 @@ void DRCEngine::buildIgnoredViolationSet() void DRCEngine::getViolationListByInterface(DETask& de_task) { - de_task.set_violation_list( - RTI.getViolationList(de_task.get_env_shape_list(), de_task.get_net_pin_shape_map(), de_task.get_net_result_map(), de_task.get_net_patch_map())); + de_task.set_violation_list(RTI.getViolationList(de_task.get_env_shape_list(), de_task.get_net_pin_shape_map(), de_task.get_net_result_map(), + de_task.get_net_patch_map(), de_task.get_check_type_set(), de_task.get_check_region_list())); } void DRCEngine::filterViolationList(DETask& de_task) @@ -236,6 +237,8 @@ std::vector DRCEngine::getExpandedViolationList(DETask& de_task, Viol new_real_rect = enlargeRect(new_real_rect, violation.get_required_size()); layer_routing_list = expandLayer(violation, {-1, 0, +1}); break; + case ViolationType::kCornerSpacing: + break; case ViolationType::kCutEOLSpacing: new_real_rect = enlargeRect(new_real_rect, violation.get_required_size()); layer_routing_list = expandLayer(violation, {0, +1}); @@ -326,6 +329,8 @@ std::vector DRCEngine::getExpandedViolationList(DETask& de_task, Viol new_real_rect = enlargeRect(new_real_rect, 0); layer_routing_list = expandLayer(violation, {0}); break; + case ViolationType::kCornerSpacing: + break; case ViolationType::kCutEOLSpacing: new_real_rect = enlargeRect(new_real_rect, 0); layer_routing_list = expandLayer(violation, {0}); diff --git a/src/operation/iRT/source/module/drc_engine/de_data_manager/DETask.hpp b/src/operation/iRT/source/module/drc_engine/de_data_manager/DETask.hpp index 04501f99fac7c5a82e9c8db9d5eabd292c882dc3..33e9e5c072adc33ad283a6e6cb644b39d483efcc 100644 --- a/src/operation/iRT/source/module/drc_engine/de_data_manager/DETask.hpp +++ b/src/operation/iRT/source/module/drc_engine/de_data_manager/DETask.hpp @@ -37,6 +37,8 @@ class DETask std::map*>>& get_net_result_map() { return _net_result_map; } std::map>& get_net_patch_map() { return _net_patch_map; } std::set& get_need_checked_net_set() { return _need_checked_net_set; } + std::set& get_check_type_set() { return _check_type_set; } + std::vector& get_check_region_list() { return _check_region_list; } std::vector& get_violation_list() { return _violation_list; } // setter void set_proc_type(const DEProcType& proc_type) { _proc_type = proc_type; } @@ -50,6 +52,8 @@ class DETask void set_net_result_map(const std::map*>>& net_result_map) { _net_result_map = net_result_map; } void set_net_patch_map(const std::map>& net_patch_map) { _net_patch_map = net_patch_map; } void set_need_checked_net_set(const std::set& need_checked_net_set) { _need_checked_net_set = need_checked_net_set; } + void set_check_type_set(const std::set& check_type_set) { _check_type_set = check_type_set; } + void set_check_region_list(const std::vector& check_region_list) { _check_region_list = check_region_list; } void set_violation_list(const std::vector& violation_list) { _violation_list = violation_list; } // function private: @@ -61,6 +65,8 @@ class DETask std::map*>> _net_result_map; std::map> _net_patch_map; std::set _need_checked_net_set; + std::set _check_type_set; + std::vector _check_region_list; std::vector _violation_list; }; diff --git a/src/operation/iRT/source/module/early_router/CMakeLists.txt b/src/operation/iRT/source/module/early_router/CMakeLists.txt index 9716aecce9b77d0126492345555bfc026741df52..7e21f465ea93dce1476171619877ef22aec6d7f5 100644 --- a/src/operation/iRT/source/module/early_router/CMakeLists.txt +++ b/src/operation/iRT/source/module/early_router/CMakeLists.txt @@ -1,9 +1,9 @@ if(DEBUG_IRT_EARLY_ROUTER) - message(STATUS "RT: DEBUG_IRT_EARLY_ROUTER") + message(STATUS "RT: DEBUG_IRT_EARLY_ROUTER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_EARLY_ROUTER") - set(CMAKE_BUILD_TYPE "Release") + message(STATUS "RT: RELEASE_IRT_EARLY_ROUTER") + set(CMAKE_BUILD_TYPE "Release") endif() add_library(irt_early_router @@ -11,15 +11,15 @@ add_library(irt_early_router ${IRT_MODULE}/early_router/EarlyRouter.cpp ) -target_link_libraries(irt_early_router +target_link_libraries(irt_early_router PUBLIC - irt_data_manager - irt_module - irt_toolkit + irt_data_manager + irt_module + irt_toolkit ) -target_include_directories(irt_early_router +target_include_directories(irt_early_router PUBLIC - ${IRT_MODULE}/early_router/er_data_manager - ${IRT_MODULE}/early_router + ${IRT_MODULE}/early_router/er_data_manager + ${IRT_MODULE}/early_router ) diff --git a/src/operation/iRT/source/module/early_router/EarlyRouter.cpp b/src/operation/iRT/source/module/early_router/EarlyRouter.cpp index 49ec7df40a200208b7dd8cd142d1b70154578643..544a75934b28c3a8a8188ae9381e1e7430930bb3 100644 --- a/src/operation/iRT/source/module/early_router/EarlyRouter.cpp +++ b/src/operation/iRT/source/module/early_router/EarlyRouter.cpp @@ -1256,8 +1256,8 @@ void EarlyRouter::updateSummary(ERModel& er_model) double& total_wire_length = summary.er_summary.total_wire_length; std::map& cut_via_num_map = summary.er_summary.cut_via_num_map; int32_t& total_via_num = summary.er_summary.total_via_num; - std::map>& clock_timing = summary.er_summary.clock_timing; - std::map& power_map = summary.er_summary.power_map; + std::map>& clock_timing_map = summary.er_summary.clock_timing_map; + std::map& type_power_map = summary.er_summary.type_power_map; std::vector>& layer_node_map = er_model.get_layer_node_map(); std::vector& er_net_list = er_model.get_er_net_list(); @@ -1270,8 +1270,8 @@ void EarlyRouter::updateSummary(ERModel& er_model) total_wire_length = 0; cut_via_num_map.clear(); total_via_num = 0; - clock_timing.clear(); - power_map.clear(); + clock_timing_map.clear(); + type_power_map.clear(); for (int32_t layer_idx = 0; layer_idx < static_cast(layer_node_map.size()); layer_idx++) { GridMap& er_node_map = layer_node_map[layer_idx]; @@ -1341,7 +1341,7 @@ void EarlyRouter::updateSummary(ERModel& er_model) routing_segment_list_list[net_idx].emplace_back(first_real_coord, second_real_coord); } } - RTI.updateTimingAndPower(real_pin_coord_map_list, routing_segment_list_list, clock_timing, power_map); + RTI.updateTimingAndPower(real_pin_coord_map_list, routing_segment_list_list, clock_timing_map, type_power_map); } } @@ -1360,8 +1360,8 @@ void EarlyRouter::printSummary(ERModel& er_model) double& total_wire_length = summary.er_summary.total_wire_length; std::map& cut_via_num_map = summary.er_summary.cut_via_num_map; int32_t& total_via_num = summary.er_summary.total_via_num; - std::map>& clock_timing = summary.er_summary.clock_timing; - std::map& power_map = summary.er_summary.power_map; + std::map>& clock_timing_map = summary.er_summary.clock_timing_map; + std::map& type_power_map = summary.er_summary.type_power_map; fort::char_table routing_demand_map_table; { @@ -1420,16 +1420,16 @@ void EarlyRouter::printSummary(ERModel& er_model) << "tns" << "wns" << "freq" << fort::endr; - for (auto& [clock_name, timing_map] : clock_timing) { + for (auto& [clock_name, timing_map] : clock_timing_map) { timing_table << clock_name << timing_map["TNS"] << timing_map["WNS"] << timing_map["Freq(MHz)"] << fort::endr; } power_table << fort::header << "power_type"; - for (auto& [type, power] : power_map) { + for (auto& [type, power] : type_power_map) { power_table << fort::header << type; } power_table << fort::endr; power_table << "power_value"; - for (auto& [type, power] : power_map) { + for (auto& [type, power] : type_power_map) { power_table << power; } power_table << fort::endr; diff --git a/src/operation/iRT/source/module/gds_plotter/CMakeLists.txt b/src/operation/iRT/source/module/gds_plotter/CMakeLists.txt index 73ba8a898953123270b9c9253fec0279a1c44c66..ebc6cab5bd965086f9e971543addad6a097955b0 100644 --- a/src/operation/iRT/source/module/gds_plotter/CMakeLists.txt +++ b/src/operation/iRT/source/module/gds_plotter/CMakeLists.txt @@ -1,8 +1,8 @@ -if(DEBUG_IRT_GDS_PLOTTER) - message(STATUS "RT: DEBUG_IRT_GDS_PLOTTER") +if(DEBUG_IRT_GDS_PLOTTER) + message(STATUS "RT: DEBUG_IRT_GDS_PLOTTER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_GDS_PLOTTER") + message(STATUS "RT: RELEASE_IRT_GDS_PLOTTER") set(CMAKE_BUILD_TYPE "Release") endif() @@ -11,15 +11,15 @@ add_library(irt_gds_plotter ${IRT_MODULE}/gds_plotter/GDSPlotter.cpp ) -target_link_libraries(irt_gds_plotter +target_link_libraries(irt_gds_plotter PUBLIC - irt_data_manager - irt_module - irt_toolkit + irt_data_manager + irt_module + irt_toolkit ) -target_include_directories(irt_gds_plotter +target_include_directories(irt_gds_plotter PUBLIC - ${IRT_MODULE}/gds_plotter/gp_data_manager - ${IRT_MODULE}/gds_plotter + ${IRT_MODULE}/gds_plotter/gp_data_manager + ${IRT_MODULE}/gds_plotter ) diff --git a/src/operation/iRT/source/module/gds_plotter/GDSPlotter.cpp b/src/operation/iRT/source/module/gds_plotter/GDSPlotter.cpp index 4e951a005c5302a543a83d92982390e57df9fd95..f68583e92fbe81ecbe9fe21bcfe5af6e6faf542f 100644 --- a/src/operation/iRT/source/module/gds_plotter/GDSPlotter.cpp +++ b/src/operation/iRT/source/module/gds_plotter/GDSPlotter.cpp @@ -136,11 +136,13 @@ void GDSPlotter::buildGraphLypFile() std::vector pattern_list = {"I5", "I9"}; std::map routing_data_type_visible_map - = {{GPDataType::kNone, false}, {GPDataType::kOpen, false}, {GPDataType::kClose, false}, {GPDataType::kInfo, false}, - {GPDataType::kNeighbor, false}, {GPDataType::kShadow, false}, {GPDataType::kKey, false}, {GPDataType::kPath, true}, - {GPDataType::kPatch, true}, {GPDataType::kShape, true}, {GPDataType::kAccessPoint, false}, {GPDataType::kAxis, false}, - {GPDataType::kRouteViolation, false}, {GPDataType::kPatchViolation, false}}; - std::map cut_data_type_visible_map = {{GPDataType::kPath, true}, {GPDataType::kShape, true}}; + = {{GPDataType::kNone, false}, {GPDataType::kOpen, false}, {GPDataType::kClose, false}, + {GPDataType::kInfo, false}, {GPDataType::kNeighbor, false}, {GPDataType::kShadow, false}, + {GPDataType::kKey, false}, {GPDataType::kGlobalPath, true}, {GPDataType::kDetailedPath, true}, + {GPDataType::kPatch, true}, {GPDataType::kShape, true}, {GPDataType::kAccessPoint, false}, + {GPDataType::kAxis, false}, {GPDataType::kOverflow, false}, {GPDataType::kRouteViolation, false}, + {GPDataType::kPatchViolation, false}}; + std::map cut_data_type_visible_map = {{GPDataType::kGlobalPath, true}, {GPDataType::kDetailedPath, true}, {GPDataType::kShape, true}}; // 0为base_region 最后一个为GCell 中间为cut+routing int32_t gds_layer_size = 2 + static_cast(_gds_routing_layer_map.size() + _gds_cut_layer_map.size()); diff --git a/src/operation/iRT/source/module/gds_plotter/gp_data_manager/GPDataType.hpp b/src/operation/iRT/source/module/gds_plotter/gp_data_manager/GPDataType.hpp index 5e19cf92df7a7181d3d21e88c512493a28199828..fa85fe99ebc14b20e24c4cad4306c4470ec74a5d 100644 --- a/src/operation/iRT/source/module/gds_plotter/gp_data_manager/GPDataType.hpp +++ b/src/operation/iRT/source/module/gds_plotter/gp_data_manager/GPDataType.hpp @@ -29,12 +29,14 @@ enum class GPDataType kNeighbor, kShadow, kKey, - kPath, + kGlobalPath, + kDetailedPath, kPatch, kShape, kAccessPoint, kBestCoord, kAxis, + kOverflow, kRouteViolation, kPatchViolation }; @@ -66,8 +68,11 @@ struct GetGPDataTypeName case GPDataType::kKey: data_type_name = "key"; break; - case GPDataType::kPath: - data_type_name = "path"; + case GPDataType::kGlobalPath: + data_type_name = "global_path"; + break; + case GPDataType::kDetailedPath: + data_type_name = "detailed_path"; break; case GPDataType::kPatch: data_type_name = "patch"; @@ -81,6 +86,9 @@ struct GetGPDataTypeName case GPDataType::kAxis: data_type_name = "axis"; break; + case GPDataType::kOverflow: + data_type_name = "overflow"; + break; case GPDataType::kRouteViolation: data_type_name = "route_violation"; break; diff --git a/src/operation/iRT/source/module/layer_assigner/CMakeLists.txt b/src/operation/iRT/source/module/layer_assigner/CMakeLists.txt index 1a5c5fd0a164dc92fb907cb37c167ebba43f1e89..66629e6d3b7f428946218d97c22e9b81c97edcab 100644 --- a/src/operation/iRT/source/module/layer_assigner/CMakeLists.txt +++ b/src/operation/iRT/source/module/layer_assigner/CMakeLists.txt @@ -1,9 +1,9 @@ if(DEBUG_IRT_LAYER_ASSIGNER) - message(STATUS "RT: DEBUG_IRT_LAYER_ASSIGNER") + message(STATUS "RT: DEBUG_IRT_LAYER_ASSIGNER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_LAYER_ASSIGNER") - set(CMAKE_BUILD_TYPE "Release") + message(STATUS "RT: RELEASE_IRT_LAYER_ASSIGNER") + set(CMAKE_BUILD_TYPE "Release") endif() add_library(irt_layer_assigner @@ -11,15 +11,15 @@ add_library(irt_layer_assigner ${IRT_MODULE}/layer_assigner/LayerAssigner.cpp ) -target_link_libraries(irt_layer_assigner +target_link_libraries(irt_layer_assigner PUBLIC - irt_data_manager - irt_module - irt_toolkit + irt_data_manager + irt_module + irt_toolkit ) -target_include_directories(irt_layer_assigner +target_include_directories(irt_layer_assigner PUBLIC - ${IRT_MODULE}/layer_assigner/la_data_manager - ${IRT_MODULE}/layer_assigner + ${IRT_MODULE}/layer_assigner/la_data_manager + ${IRT_MODULE}/layer_assigner ) diff --git a/src/operation/iRT/source/module/layer_assigner/LayerAssigner.cpp b/src/operation/iRT/source/module/layer_assigner/LayerAssigner.cpp index 04db0acbc41b0c6ea1823f30408a8a156f880e21..339d57619a30ace886ffdb519153551dde573acf 100644 --- a/src/operation/iRT/source/module/layer_assigner/LayerAssigner.cpp +++ b/src/operation/iRT/source/module/layer_assigner/LayerAssigner.cpp @@ -61,15 +61,15 @@ void LayerAssigner::assign() buildLANodeNeighbor(la_model); buildOrientSupply(la_model); // debugCheckLAModel(la_model); - buildTopoTree(la_model); + buildPlaneTree(la_model); routeLAModel(la_model); + // debugPlotLAModel(la_model, "after"); updateSummary(la_model); printSummary(la_model); outputGuide(la_model); outputNetCSV(la_model); outputOverflowCSV(la_model); - outputNetJson(la_model); - outputOverflowJson(la_model); + outputJson(la_model); RTLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); } @@ -111,19 +111,18 @@ LANet LayerAssigner::convertToLANet(Net& net) void LayerAssigner::setLAComParam(LAModel& la_model) { - int32_t topo_spilt_length = 10; + int32_t topo_spilt_length = 1; double prefer_wire_unit = 1; double non_prefer_wire_unit = 2.5 * prefer_wire_unit; double via_unit = 2 * non_prefer_wire_unit; double overflow_unit = 4 * non_prefer_wire_unit; /** - * topo_spilt_length, prefer_wire_unit, via_unit, overflow_unit + * topo_spilt_length, via_unit, overflow_unit */ // clang-format off - LAComParam la_com_param(topo_spilt_length, prefer_wire_unit, via_unit, overflow_unit); + LAComParam la_com_param(topo_spilt_length, via_unit, overflow_unit); // clang-format on RTLOG.info(Loc::current(), "topo_spilt_length: ", la_com_param.get_topo_spilt_length()); - RTLOG.info(Loc::current(), "prefer_wire_unit: ", la_com_param.get_prefer_wire_unit()); RTLOG.info(Loc::current(), "via_unit: ", la_com_param.get_via_unit()); RTLOG.info(Loc::current(), "overflow_unit: ", la_com_param.get_overflow_unit()); la_model.set_la_com_param(la_com_param); @@ -162,6 +161,9 @@ void LayerAssigner::buildLayerNodeMap(LAModel& la_model) la_node.set_boundary_wire_unit(gcell_map[x][y].get_boundary_wire_unit()); la_node.set_internal_wire_unit(gcell_map[x][y].get_internal_wire_unit()); la_node.set_internal_via_unit(gcell_map[x][y].get_internal_via_unit()); + if (RTUTIL.exist(gcell_map[x][y].get_routing_ignore_net_orient_map(), layer_idx)) { + la_node.set_ignore_net_orient_map(gcell_map[x][y].get_routing_ignore_net_orient_map()[layer_idx]); + } } } } @@ -243,7 +245,7 @@ void LayerAssigner::buildOrientSupply(LAModel& la_model) RTLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); } -void LayerAssigner::buildTopoTree(LAModel& la_model) +void LayerAssigner::buildPlaneTree(LAModel& la_model) { Monitor monitor; RTLOG.info(Loc::current(), "Starting..."); @@ -267,7 +269,7 @@ void LayerAssigner::buildTopoTree(LAModel& la_model) candidate_root_coord_list.push_back(coord); key_coord_pin_map[coord].insert(static_cast(i)); } - la_net.set_topo_tree(RTUTIL.getTreeByFullFlow(candidate_root_coord_list, routing_segment_list, key_coord_pin_map)); + la_net.set_planar_tree(RTUTIL.getTreeByFullFlow(candidate_root_coord_list, routing_segment_list, key_coord_pin_map)); } for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { for (Segment* segment : segment_set) { @@ -301,19 +303,12 @@ void LayerAssigner::routeLAModel(LAModel& la_model) void LayerAssigner::routeLATask(LAModel& la_model, LANet* la_task) { initSingleTask(la_model, la_task); - // 构建la_topo_list,并将通孔线段加入routing_segment_list - std::vector la_topo_list; - std::vector> routing_segment_list; - makeLATopoList(la_model, la_topo_list, routing_segment_list); - for (LATopo& la_topo : la_topo_list) { - routeLATopo(la_model, &la_topo); - for (Segment& routing_segment : la_topo.get_routing_segment_list()) { - routing_segment_list.push_back(routing_segment); - } + if (needRouting(la_model)) { + spiltPlaneTree(la_model); + buildPillarTree(la_model); + assignPillarTree(la_model); + buildLayerTree(la_model); } - MTree coord_tree = getCoordTree(la_model, routing_segment_list); - updateDemandToGraph(la_model, ChangeType::kAdd, coord_tree); - uploadNetResult(la_model, coord_tree); resetSingleTask(la_model); } @@ -322,509 +317,365 @@ void LayerAssigner::initSingleTask(LAModel& la_model, LANet* la_task) la_model.set_curr_la_task(la_task); } -void LayerAssigner::makeLATopoList(LAModel& la_model, std::vector& la_topo_list, std::vector>& routing_segment_list) +bool LayerAssigner::needRouting(LAModel& la_model) +{ + return (la_model.get_curr_la_task()->get_planar_tree().get_root() != nullptr); +} + +void LayerAssigner::spiltPlaneTree(LAModel& la_model) { - int32_t bottom_routing_layer_idx = RTDM.getConfig().bottom_routing_layer_idx; - int32_t top_routing_layer_idx = RTDM.getConfig().top_routing_layer_idx; int32_t topo_spilt_length = la_model.get_la_com_param().get_topo_spilt_length(); - LANet* curr_la_task = la_model.get_curr_la_task(); - if (curr_la_task->get_topo_tree().get_root() == nullptr) { - LATopo la_topo; - for (LAPin& la_pin : curr_la_task->get_la_pin_list()) { - LAGroup la_group; - la_group.get_coord_list().push_back(la_pin.get_access_point().getGridLayerCoord()); - la_topo.get_la_group_list().push_back(la_group); - } - la_topo_list.push_back(la_topo); - { - std::set coord_set; - for (LATopo& la_topo : la_topo_list) { - for (LAGroup& la_group : la_topo.get_la_group_list()) { - for (LayerCoord& coord : la_group.get_coord_list()) { - coord_set.insert(coord); - } - } - } - if (coord_set.size() > 1) { - RTLOG.error(Loc::current(), "The topo_tree should not be empty!"); - } - } - } else { - // planar_topo_list - std::vector> planar_topo_list; - { - for (Segment*>& coord_segment : RTUTIL.getSegListByTree(curr_la_task->get_topo_tree())) { - PlanarCoord& first_coord = coord_segment.get_first()->value(); - PlanarCoord& second_coord = coord_segment.get_second()->value(); - int32_t first_x = first_coord.get_x(); - int32_t first_y = first_coord.get_y(); - int32_t second_x = second_coord.get_x(); - int32_t second_y = second_coord.get_y(); - - if (first_x == second_x) { - int32_t y_diff = std::abs(second_y - first_y); - int32_t segment_num = std::max(1, static_cast(std::ceil(y_diff / topo_spilt_length))); - int32_t step = (second_y - first_y) / segment_num; - for (int32_t i = 0; i < segment_num; ++i) { - PlanarCoord start(first_x, first_y + i * step); - PlanarCoord end(first_x, first_y + (i + 1) * step); - planar_topo_list.emplace_back(start, end); - } - // Add the last segment to reach the exact second_coord - if (planar_topo_list.back().get_second().get_y() != second_y) { - planar_topo_list.emplace_back(planar_topo_list.back().get_second(), second_coord); - } - } else if (first_y == second_y) { - int32_t x_diff = std::abs(second_x - first_x); - int32_t segment_num = std::max(1, static_cast(std::ceil(x_diff / topo_spilt_length))); - int32_t step = (second_x - first_x) / segment_num; - for (int32_t i = 0; i < segment_num; ++i) { - PlanarCoord start(first_x + i * step, first_y); - PlanarCoord end(first_x + (i + 1) * step, first_y); - planar_topo_list.emplace_back(start, end); - } - if (planar_topo_list.back().get_second().get_x() != second_x) { - planar_topo_list.emplace_back(planar_topo_list.back().get_second(), second_coord); - } - } else { - RTLOG.error(Loc::current(), "The segment is not horizontal or vertical!"); - } + TNode* planar_tree_root = la_model.get_curr_la_task()->get_planar_tree().get_root(); + std::queue*> planar_queue = RTUTIL.initQueue(planar_tree_root); + while (!planar_queue.empty()) { + TNode* planar_node = RTUTIL.getFrontAndPop(planar_queue); + std::vector*> child_list = planar_node->get_child_list(); + for (size_t i = 0; i < child_list.size(); i++) { + int32_t length = RTUTIL.getManhattanDistance(planar_node->value().get_planar_coord(), child_list[i]->value().get_planar_coord()); + if (length <= topo_spilt_length) { + continue; } + insertMidPoint(la_model, planar_node, child_list[i]); } - // planar_pin_group_map - std::map, CmpPlanarCoordByXASC> planar_pin_group_map; - { - for (LAPin& la_pin : curr_la_task->get_la_pin_list()) { - LayerCoord grid_coord = la_pin.get_access_point().getGridLayerCoord(); + RTUTIL.addListToQueue(planar_queue, child_list); + } +} - LAGroup la_group; - la_group.get_coord_list().push_back(grid_coord); - planar_pin_group_map[grid_coord.get_planar_coord()].push_back(la_group); - } +void LayerAssigner::insertMidPoint(LAModel& la_model, TNode* planar_node, TNode* child_node) +{ + int32_t topo_spilt_length = la_model.get_la_com_param().get_topo_spilt_length(); + + PlanarCoord& parent_coord = planar_node->value().get_planar_coord(); + PlanarCoord& child_coord = child_node->value().get_planar_coord(); + if (RTUTIL.isProximal(parent_coord, child_coord)) { + return; + } + std::vector mid_coord_list; + int32_t x1 = parent_coord.get_x(); + int32_t x2 = child_coord.get_x(); + int32_t y1 = parent_coord.get_y(); + int32_t y2 = child_coord.get_y(); + if (RTUTIL.isHorizontal(parent_coord, child_coord)) { + RTUTIL.swapByASC(x1, x2); + for (int32_t x = x1 + topo_spilt_length; x < x2; x += topo_spilt_length) { + mid_coord_list.emplace_back(x, y1); } - // planar_steiner_group_map - std::map planar_steiner_group_map; - { - for (Segment& planar_topo : planar_topo_list) { - for (PlanarCoord coord : {planar_topo.get_first(), planar_topo.get_second()}) { - if (!RTUTIL.exist(planar_pin_group_map, coord) && !RTUTIL.exist(planar_steiner_group_map, coord)) { - // 补充steiner point的垂直线段 - routing_segment_list.emplace_back(LayerCoord(coord, bottom_routing_layer_idx), LayerCoord(coord, top_routing_layer_idx)); - for (int32_t layer_idx = bottom_routing_layer_idx; layer_idx <= top_routing_layer_idx; layer_idx++) { - planar_steiner_group_map[coord].get_coord_list().push_back(LayerCoord(coord, layer_idx)); - } - } - } + if (parent_coord.get_x() > child_coord.get_x()) { + for (size_t i = 0, j = mid_coord_list.size() - 1; i < j; i++, j--) { + std::swap(mid_coord_list[i], mid_coord_list[j]); } } - // 生成topo group - { - for (Segment& planar_topo : planar_topo_list) { - LATopo la_topo; - for (PlanarCoord coord : {planar_topo.get_first(), planar_topo.get_second()}) { - if (RTUTIL.exist(planar_pin_group_map, coord)) { - for (LAGroup& la_group : planar_pin_group_map[coord]) { - la_topo.get_la_group_list().push_back(la_group); - } - } else if (RTUTIL.exist(planar_steiner_group_map, coord)) { - la_topo.get_la_group_list().push_back(planar_steiner_group_map[coord]); - } - } - la_topo_list.push_back(la_topo); - } + } else if (RTUTIL.isVertical(parent_coord, child_coord)) { + RTUTIL.swapByASC(y1, y2); + for (int32_t y = y1 + topo_spilt_length; y < y2; y += topo_spilt_length) { + mid_coord_list.emplace_back(x1, y); } - } - // 构建topo的其他内容 - { - for (LATopo& la_topo : la_topo_list) { - la_topo.set_net_idx(curr_la_task->get_net_idx()); - std::vector coord_list; - for (LAGroup& la_group : la_topo.get_la_group_list()) { - for (LayerCoord& coord : la_group.get_coord_list()) { - coord_list.push_back(coord); - } + if (parent_coord.get_y() > child_coord.get_y()) { + for (size_t i = 0, j = mid_coord_list.size() - 1; i < j; i++, j--) { + std::swap(mid_coord_list[i], mid_coord_list[j]); } - la_topo.set_bounding_box(RTUTIL.getBoundingBox(coord_list)); } + } else { + RTLOG.error(Loc::current(), "The segment is oblique!"); } + planar_node->delChild(child_node); + TNode* curr_node = planar_node; + for (size_t i = 0; i < mid_coord_list.size(); i++) { + LayerCoord mid_coord(mid_coord_list[i], 0); + TNode* mid_node = new TNode(mid_coord); + curr_node->addChild(mid_node); + curr_node = mid_node; + } + curr_node->addChild(child_node); } -void LayerAssigner::routeLATopo(LAModel& la_model, LATopo* la_topo) -{ - initSingleTopo(la_model, la_topo); - while (!isConnectedAllEnd(la_model)) { - routeSinglePath(la_model); - updatePathResult(la_model); - resetStartAndEnd(la_model); - resetSinglePath(la_model); - } - updateTopoResult(la_model); - resetSingleTopo(la_model); -} - -void LayerAssigner::initSingleTopo(LAModel& la_model, LATopo* la_topo) +void LayerAssigner::buildPillarTree(LAModel& la_model) { - std::vector>& layer_node_map = la_model.get_layer_node_map(); + LANet* curr_la_task = la_model.get_curr_la_task(); - // single topo - la_model.set_curr_la_topo(la_topo); - { - std::vector> node_list_list; - std::vector& la_group_list = la_topo->get_la_group_list(); - for (LAGroup& la_group : la_group_list) { - std::vector node_list; - for (LayerCoord& coord : la_group.get_coord_list()) { - LANode& la_node = layer_node_map[coord.get_layer_idx()][coord.get_x()][coord.get_y()]; - node_list.push_back(&la_node); - } - node_list_list.push_back(node_list); - } - for (size_t i = 0; i < node_list_list.size(); i++) { - if (i == 0) { - la_model.get_start_node_list_list().push_back(node_list_list[i]); - } else { - la_model.get_end_node_list_list().push_back(node_list_list[i]); - } - } + std::map, CmpPlanarCoordByXASC> coord_pin_layer_map; + for (LAPin& la_pin : curr_la_task->get_la_pin_list()) { + AccessPoint& access_point = la_pin.get_access_point(); + coord_pin_layer_map[access_point.get_grid_coord()].insert(access_point.get_layer_idx()); } - la_model.get_path_node_list().clear(); - la_model.get_single_topo_visited_node_list().clear(); - la_model.get_routing_segment_list().clear(); + std::function, CmpPlanarCoordByXASC>&)> convert; + convert = std::bind(&LayerAssigner::convertLAPillar, this, std::placeholders::_1, std::placeholders::_2); + curr_la_task->set_pillar_tree(RTUTIL.convertTree(curr_la_task->get_planar_tree(), convert, coord_pin_layer_map)); } -bool LayerAssigner::isConnectedAllEnd(LAModel& la_model) +LAPillar LayerAssigner::convertLAPillar(LayerCoord& layer_coord, std::map, CmpPlanarCoordByXASC>& coord_pin_layer_map) { - return la_model.get_end_node_list_list().empty(); + LAPillar la_pillar; + la_pillar.set_planar_coord(layer_coord.get_planar_coord()); + la_pillar.set_pin_layer_idx_set(coord_pin_layer_map[layer_coord.get_planar_coord()]); + return la_pillar; } -void LayerAssigner::routeSinglePath(LAModel& la_model) +void LayerAssigner::assignPillarTree(LAModel& la_model) { - initPathHead(la_model); - while (!searchEnded(la_model)) { - expandSearching(la_model); - resetPathHead(la_model); - } + assignForward(la_model); + assignBackward(la_model); } -void LayerAssigner::initPathHead(LAModel& la_model) +void LayerAssigner::assignForward(LAModel& la_model) { - std::vector>& start_node_list_list = la_model.get_start_node_list_list(); - std::vector& path_node_list = la_model.get_path_node_list(); - - for (std::vector& start_node_list : start_node_list_list) { - for (LANode* start_node : start_node_list) { - start_node->set_estimated_cost(getEstimateCostToEnd(la_model, start_node)); - pushToOpenList(la_model, start_node); - } - } - for (LANode* path_node : path_node_list) { - path_node->set_estimated_cost(getEstimateCostToEnd(la_model, path_node)); - pushToOpenList(la_model, path_node); + TNode* pillar_tree_root = la_model.get_curr_la_task()->get_pillar_tree().get_root(); + + LAPackage la_package(pillar_tree_root, pillar_tree_root); + for (int32_t candidate_layer_idx : getCandidateLayerList(la_model, la_package)) { + std::set& pin_layer_idx_set = pillar_tree_root->value().get_pin_layer_idx_set(); + LALayerCost layer_cost; + layer_cost.set_parent_layer_idx(candidate_layer_idx); + layer_cost.set_layer_idx(candidate_layer_idx); + layer_cost.set_history_cost(getFullViaCost(la_model, pin_layer_idx_set, candidate_layer_idx)); + pillar_tree_root->value().get_layer_cost_list().push_back(std::move(layer_cost)); } - resetPathHead(la_model); -} - -bool LayerAssigner::searchEnded(LAModel& la_model) -{ - std::vector>& end_node_list_list = la_model.get_end_node_list_list(); - LANode* path_head_node = la_model.get_path_head_node(); - - if (path_head_node == nullptr) { - la_model.set_end_node_list_idx(-1); - return true; - } - for (size_t i = 0; i < end_node_list_list.size(); i++) { - for (LANode* end_node : end_node_list_list[i]) { - if (path_head_node == end_node) { - la_model.set_end_node_list_idx(static_cast(i)); - return true; - } + std::queue*> pillar_node_queue = RTUTIL.initQueue(pillar_tree_root); + while (!pillar_node_queue.empty()) { + TNode* parent_pillar_node = RTUTIL.getFrontAndPop(pillar_node_queue); + std::vector*>& child_list = parent_pillar_node->get_child_list(); + for (size_t i = 0; i < child_list.size(); i++) { + LAPackage la_package(parent_pillar_node, child_list[i]); + buildLayerCost(la_model, la_package); } + RTUTIL.addListToQueue(pillar_node_queue, child_list); } - return false; } -void LayerAssigner::expandSearching(LAModel& la_model) +std::vector LayerAssigner::getCandidateLayerList(LAModel& la_model, LAPackage& la_package) { - PriorityQueue, CmpLANodeCost>& open_queue = la_model.get_open_queue(); - LANode* path_head_node = la_model.get_path_head_node(); + std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); + int32_t bottom_routing_layer_idx = RTDM.getConfig().bottom_routing_layer_idx; + int32_t top_routing_layer_idx = RTDM.getConfig().top_routing_layer_idx; - for (auto& [orientation, neighbor_node] : path_head_node->get_neighbor_node_map()) { - if (neighbor_node == nullptr) { - continue; - } - if (!RTUTIL.isInside(la_model.get_curr_la_topo()->get_bounding_box(), *neighbor_node)) { - continue; - } - if (neighbor_node->isClose()) { + Direction direction = RTUTIL.getDirection(la_package.getParentPillar().get_planar_coord(), la_package.getChildPillar().get_planar_coord()); + + std::vector candidate_layer_idx_list; + for (RoutingLayer& routing_layer : routing_layer_list) { + if (routing_layer.get_layer_idx() < bottom_routing_layer_idx || top_routing_layer_idx < routing_layer.get_layer_idx()) { continue; } - double known_cost = getKnownCost(la_model, path_head_node, neighbor_node); - if (neighbor_node->isOpen() && known_cost < neighbor_node->get_known_cost()) { - neighbor_node->set_known_cost(known_cost); - neighbor_node->set_parent_node(path_head_node); - // 对优先队列中的值修改了,需要重新建堆 - std::make_heap(open_queue.begin(), open_queue.end(), CmpLANodeCost()); - } else if (neighbor_node->isNone()) { - neighbor_node->set_known_cost(known_cost); - neighbor_node->set_parent_node(path_head_node); - neighbor_node->set_estimated_cost(getEstimateCostToEnd(la_model, neighbor_node)); - pushToOpenList(la_model, neighbor_node); + if (direction == Direction::kProximal) { + candidate_layer_idx_list.push_back(routing_layer.get_layer_idx()); + } else if (direction == routing_layer.get_prefer_direction()) { + candidate_layer_idx_list.push_back(routing_layer.get_layer_idx()); } } + return candidate_layer_idx_list; } -void LayerAssigner::resetPathHead(LAModel& la_model) +double LayerAssigner::getFullViaCost(LAModel& la_model, std::set& layer_idx_set, int32_t candidate_layer_idx) { - la_model.set_path_head_node(popFromOpenList(la_model)); -} + double via_unit = la_model.get_la_com_param().get_via_unit(); -void LayerAssigner::updatePathResult(LAModel& la_model) -{ - for (Segment& routing_segment : getRoutingSegmentListByNode(la_model.get_path_head_node())) { - la_model.get_routing_segment_list().push_back(routing_segment); + int32_t via_num = 0; + if (layer_idx_set.size() > 0) { + std::set layer_idx_set_temp = layer_idx_set; + layer_idx_set_temp.insert(candidate_layer_idx); + via_num = std::abs(*layer_idx_set_temp.begin() - *layer_idx_set_temp.rbegin()); } + return (via_unit * via_num); } -std::vector> LayerAssigner::getRoutingSegmentListByNode(LANode* node) +void LayerAssigner::buildLayerCost(LAModel& la_model, LAPackage& la_package) { - std::vector> routing_segment_list; - - LANode* curr_node = node; - LANode* pre_node = curr_node->get_parent_node(); - - if (pre_node == nullptr) { - // 起点和终点重合 - return routing_segment_list; - } - Orientation curr_orientation = RTUTIL.getOrientation(*curr_node, *pre_node); - while (pre_node->get_parent_node() != nullptr) { - Orientation pre_orientation = RTUTIL.getOrientation(*pre_node, *pre_node->get_parent_node()); - if (curr_orientation != pre_orientation) { - routing_segment_list.emplace_back(*curr_node, *pre_node); - curr_orientation = pre_orientation; - curr_node = pre_node; - } - pre_node = pre_node->get_parent_node(); + std::vector& layer_cost_list = la_package.getChildPillar().get_layer_cost_list(); + + for (int32_t candidate_layer_idx : getCandidateLayerList(la_model, la_package)) { + std::pair parent_pillar_cost_pair = getParentPillarCost(la_model, la_package, candidate_layer_idx); + double segment_cost = getSegmentCost(la_model, la_package, candidate_layer_idx); + double child_pillar_cost = getChildPillarCost(la_model, la_package, candidate_layer_idx); + + LALayerCost layer_cost; + layer_cost.set_parent_layer_idx(parent_pillar_cost_pair.first); + layer_cost.set_layer_idx(candidate_layer_idx); + layer_cost.set_history_cost(parent_pillar_cost_pair.second + segment_cost + child_pillar_cost); + layer_cost_list.push_back(std::move(layer_cost)); } - routing_segment_list.emplace_back(*curr_node, *pre_node); - - return routing_segment_list; } -void LayerAssigner::resetStartAndEnd(LAModel& la_model) +std::pair LayerAssigner::getParentPillarCost(LAModel& la_model, LAPackage& la_package, int32_t candidate_layer_idx) { - std::vector>& start_node_list_list = la_model.get_start_node_list_list(); - std::vector>& end_node_list_list = la_model.get_end_node_list_list(); - std::vector& path_node_list = la_model.get_path_node_list(); - LANode* path_head_node = la_model.get_path_head_node(); - int32_t end_node_list_idx = la_model.get_end_node_list_idx(); - - // 对于抵达的终点pin,只保留到达的node - end_node_list_list[end_node_list_idx].clear(); - end_node_list_list[end_node_list_idx].push_back(path_head_node); - - LANode* path_node = path_head_node->get_parent_node(); - if (path_node == nullptr) { - // 起点和终点重合 - path_node = path_head_node; - } else { - // 起点和终点不重合 - while (path_node->get_parent_node() != nullptr) { - path_node_list.push_back(path_node); - path_node = path_node->get_parent_node(); + LAPillar& parent_pillar = la_package.getParentPillar(); + + std::pair layer_cost_pair; + double min_cost = DBL_MAX; + for (LALayerCost& layer_cost : parent_pillar.get_layer_cost_list()) { + std::set layer_idx_set_temp = parent_pillar.get_pin_layer_idx_set(); + layer_idx_set_temp.insert(layer_cost.get_layer_idx()); + double curr_cost = layer_cost.get_history_cost() + getExtraViaCost(la_model, layer_idx_set_temp, candidate_layer_idx); + + if (curr_cost < min_cost) { + min_cost = curr_cost; + layer_cost_pair.first = layer_cost.get_layer_idx(); + layer_cost_pair.second = curr_cost; + } else if (curr_cost == min_cost) { + layer_cost_pair.first = std::min(layer_cost_pair.first, layer_cost.get_layer_idx()); } } - if (start_node_list_list.size() == 1) { - start_node_list_list.front().clear(); - start_node_list_list.front().push_back(path_node); + if (min_cost == DBL_MAX) { + RTLOG.error(Loc::current(), "The min cost is wrong!"); } - start_node_list_list.push_back(end_node_list_list[end_node_list_idx]); - end_node_list_list.erase(end_node_list_list.begin() + end_node_list_idx); + return layer_cost_pair; } -void LayerAssigner::resetSinglePath(LAModel& la_model) +double LayerAssigner::getExtraViaCost(LAModel& la_model, std::set& layer_idx_set, int32_t candidate_layer_idx) { - PriorityQueue, CmpLANodeCost> empty_queue; - la_model.set_open_queue(empty_queue); + double via_unit = la_model.get_la_com_param().get_via_unit(); - std::vector& single_path_visited_node_list = la_model.get_single_path_visited_node_list(); - for (LANode* visited_node : single_path_visited_node_list) { - visited_node->set_state(LANodeState::kNone); - visited_node->set_parent_node(nullptr); - visited_node->set_known_cost(0); - visited_node->set_estimated_cost(0); + int32_t via_num = 0; + if (layer_idx_set.size() > 0) { + int32_t begin_layer_idx = *layer_idx_set.begin(); + int32_t end_layer_idx = *layer_idx_set.rbegin(); + if (candidate_layer_idx < begin_layer_idx) { + via_num = std::abs(candidate_layer_idx - begin_layer_idx); + } else if (end_layer_idx < candidate_layer_idx) { + via_num = std::abs(candidate_layer_idx - end_layer_idx); + } else { + via_num = 0; + } } - single_path_visited_node_list.clear(); - - la_model.set_path_head_node(nullptr); - la_model.set_end_node_list_idx(-1); + return (via_unit * via_num); } -void LayerAssigner::updateTopoResult(LAModel& la_model) +double LayerAssigner::getSegmentCost(LAModel& la_model, LAPackage& la_package, int32_t candidate_layer_idx) { - la_model.get_curr_la_topo()->set_routing_segment_list(getRoutingSegmentList(la_model)); -} + std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); + std::vector>& layer_node_map = la_model.get_layer_node_map(); + double overflow_unit = la_model.get_la_com_param().get_overflow_unit(); -std::vector> LayerAssigner::getRoutingSegmentList(LAModel& la_model) -{ - LATopo* curr_la_topo = la_model.get_curr_la_topo(); + Direction prefer_direction = routing_layer_list[candidate_layer_idx].get_prefer_direction(); - std::vector candidate_root_coord_list; - std::map, CmpLayerCoordByXASC> key_coord_pin_map; - std::vector& la_group_list = curr_la_topo->get_la_group_list(); - for (size_t i = 0; i < la_group_list.size(); i++) { - for (LayerCoord& coord : la_group_list[i].get_coord_list()) { - candidate_root_coord_list.push_back(coord); - key_coord_pin_map[coord].insert(static_cast(i)); - } - } - MTree coord_tree = RTUTIL.getTreeByFullFlow(candidate_root_coord_list, la_model.get_routing_segment_list(), key_coord_pin_map); + PlanarCoord first_coord = la_package.getParentPillar().get_planar_coord(); + PlanarCoord second_coord = la_package.getChildPillar().get_planar_coord(); + int32_t first_x = first_coord.get_x(); + int32_t first_y = first_coord.get_y(); + int32_t second_x = second_coord.get_x(); + int32_t second_y = second_coord.get_y(); + RTUTIL.swapByASC(first_x, second_x); + RTUTIL.swapByASC(first_y, second_y); - std::vector> routing_segment_list; - for (Segment*>& coord_segment : RTUTIL.getSegListByTree(coord_tree)) { - routing_segment_list.emplace_back(coord_segment.get_first()->value(), coord_segment.get_second()->value()); + double node_cost = 0; + for (int32_t x = first_x; x <= second_x; x++) { + for (int32_t y = first_y; y <= second_y; y++) { + node_cost += layer_node_map[candidate_layer_idx][x][y].getOverflowCost(la_model.get_curr_la_task()->get_net_idx(), prefer_direction, overflow_unit); + } } - return routing_segment_list; -} - -void LayerAssigner::resetSingleTopo(LAModel& la_model) -{ - la_model.set_curr_la_topo(nullptr); - la_model.get_start_node_list_list().clear(); - la_model.get_end_node_list_list().clear(); - la_model.get_path_node_list().clear(); - la_model.get_single_topo_visited_node_list().clear(); - la_model.get_routing_segment_list().clear(); + return node_cost; } -// manager open list - -void LayerAssigner::pushToOpenList(LAModel& la_model, LANode* curr_node) +double LayerAssigner::getChildPillarCost(LAModel& la_model, LAPackage& la_package, int32_t candidate_layer_idx) { - PriorityQueue, CmpLANodeCost>& open_queue = la_model.get_open_queue(); - std::vector& single_topo_visited_node_list = la_model.get_single_topo_visited_node_list(); - std::vector& single_path_visited_node_list = la_model.get_single_path_visited_node_list(); - - open_queue.push(curr_node); - curr_node->set_state(LANodeState::kOpen); - single_topo_visited_node_list.push_back(curr_node); - single_path_visited_node_list.push_back(curr_node); + LAPillar& child_pillar = la_package.getChildPillar(); + return getFullViaCost(la_model, child_pillar.get_pin_layer_idx_set(), candidate_layer_idx); } -LANode* LayerAssigner::popFromOpenList(LAModel& la_model) +void LayerAssigner::assignBackward(LAModel& la_model) { - PriorityQueue, CmpLANodeCost>& open_queue = la_model.get_open_queue(); - - LANode* node = nullptr; - if (!open_queue.empty()) { - node = open_queue.top(); - open_queue.pop(); - node->set_state(LANodeState::kClose); + std::vector*>> level_list = RTUTIL.getLevelOrder(la_model.get_curr_la_task()->get_pillar_tree()); + if (level_list.empty()) { + return; + } + for (int32_t i = static_cast(level_list.size() - 1); i >= 0; i--) { + for (size_t j = 0; j < level_list[i].size(); j++) { + int32_t best_layer_idx; + if (level_list[i][j]->isLeafNode()) { + best_layer_idx = getBestLayerBySelf(level_list[i][j]); + } else { + best_layer_idx = getBestLayerByChild(level_list[i][j]); + } + level_list[i][j]->value().set_layer_idx(best_layer_idx); + } } - return node; } -// calculate known - -double LayerAssigner::getKnownCost(LAModel& la_model, LANode* start_node, LANode* end_node) +int32_t LayerAssigner::getBestLayerBySelf(TNode* pillar_node) { - bool exist_neighbor = false; - for (auto& [orientation, neighbor_ptr] : start_node->get_neighbor_node_map()) { - if (neighbor_ptr == end_node) { - exist_neighbor = true; - break; + std::vector& layer_cost_list = pillar_node->value().get_layer_cost_list(); + + double min_cost = DBL_MAX; + int32_t best_layer_idx = layer_cost_list.front().get_layer_idx(); + for (LALayerCost& layer_cost : layer_cost_list) { + double cost = layer_cost.get_history_cost(); + if (cost < min_cost) { + min_cost = cost; + best_layer_idx = layer_cost.get_layer_idx(); + } else if (cost == min_cost) { + best_layer_idx = std::min(best_layer_idx, layer_cost.get_layer_idx()); } } - if (!exist_neighbor) { - RTLOG.error(Loc::current(), "The neighbor not exist!"); + if (min_cost == DBL_MAX) { + RTLOG.error(Loc::current(), "The min cost is wrong!"); } - - double cost = 0; - cost += start_node->get_known_cost(); - cost += getNodeCost(la_model, start_node, RTUTIL.getOrientation(*start_node, *end_node)); - cost += getNodeCost(la_model, end_node, RTUTIL.getOrientation(*end_node, *start_node)); - cost += getKnownWireCost(la_model, start_node, end_node); - cost += getKnownViaCost(la_model, start_node, end_node); - return cost; + return best_layer_idx; } -double LayerAssigner::getNodeCost(LAModel& la_model, LANode* curr_node, Orientation orientation) +int32_t LayerAssigner::getBestLayerByChild(TNode* parent_pillar_node) { - double overflow_unit = la_model.get_la_com_param().get_overflow_unit(); - int32_t curr_net_idx = la_model.get_curr_la_topo()->get_net_idx(); - - double node_cost = 0; - node_cost += curr_node->getOverflowCost(curr_net_idx, orientation, overflow_unit); - return node_cost; -} - -double LayerAssigner::getKnownWireCost(LAModel& la_model, LANode* start_node, LANode* end_node) -{ - std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); - double prefer_wire_unit = la_model.get_la_com_param().get_prefer_wire_unit(); - - double wire_cost = 0; - if (start_node->get_layer_idx() == end_node->get_layer_idx()) { - wire_cost += RTUTIL.getManhattanDistance(start_node->get_planar_coord(), end_node->get_planar_coord()); - - RoutingLayer& routing_layer = routing_layer_list[start_node->get_layer_idx()]; - if (routing_layer.get_prefer_direction() == RTUTIL.getDirection(*start_node, *end_node)) { - wire_cost *= prefer_wire_unit; + std::set candidate_layer_idx_set; + for (TNode* child_node : parent_pillar_node->get_child_list()) { + for (LALayerCost& layer_cost : child_node->value().get_layer_cost_list()) { + if (layer_cost.get_layer_idx() == child_node->value().get_layer_idx()) { + candidate_layer_idx_set.insert(layer_cost.get_parent_layer_idx()); + } } } - return wire_cost; -} - -double LayerAssigner::getKnownViaCost(LAModel& la_model, LANode* start_node, LANode* end_node) -{ - double via_unit = la_model.get_la_com_param().get_via_unit(); - double via_cost = (via_unit * std::abs(start_node->get_layer_idx() - end_node->get_layer_idx())); - return via_cost; -} - -// calculate estimate - -double LayerAssigner::getEstimateCostToEnd(LAModel& la_model, LANode* curr_node) -{ - std::vector>& end_node_list_list = la_model.get_end_node_list_list(); - - double estimate_cost = DBL_MAX; - for (std::vector& end_node_list : end_node_list_list) { - for (LANode* end_node : end_node_list) { - if (end_node->isClose()) { + double min_cost = DBL_MAX; + int32_t best_layer_idx = INT_MAX; + for (int32_t candidate_layer_idx : candidate_layer_idx_set) { + for (LALayerCost& layer_cost : parent_pillar_node->value().get_layer_cost_list()) { + if (layer_cost.get_layer_idx() != candidate_layer_idx) { continue; } - estimate_cost = std::min(estimate_cost, getEstimateCost(la_model, curr_node, end_node)); + double curr_cost = layer_cost.get_history_cost(); + if (curr_cost < min_cost) { + min_cost = curr_cost; + best_layer_idx = candidate_layer_idx; + } else if (curr_cost == min_cost) { + best_layer_idx = std::min(best_layer_idx, candidate_layer_idx); + } + break; } } - return estimate_cost; + if (min_cost == DBL_MAX) { + RTLOG.error(Loc::current(), "The min cost is wrong!"); + } + return best_layer_idx; } -double LayerAssigner::getEstimateCost(LAModel& la_model, LANode* start_node, LANode* end_node) +void LayerAssigner::buildLayerTree(LAModel& la_model) { - double estimate_cost = 0; - estimate_cost += getEstimateWireCost(la_model, start_node, end_node); - estimate_cost += getEstimateViaCost(la_model, start_node, end_node); - return estimate_cost; + std::vector> routing_segment_list = getRoutingSegmentList(la_model); + MTree coord_tree = getCoordTree(la_model, routing_segment_list); + updateDemandToGraph(la_model, ChangeType::kAdd, coord_tree); + uploadNetResult(la_model, coord_tree); } -double LayerAssigner::getEstimateWireCost(LAModel& la_model, LANode* start_node, LANode* end_node) +std::vector> LayerAssigner::getRoutingSegmentList(LAModel& la_model) { - double prefer_wire_unit = la_model.get_la_com_param().get_prefer_wire_unit(); - - double wire_cost = 0; - wire_cost += RTUTIL.getManhattanDistance(start_node->get_planar_coord(), end_node->get_planar_coord()); - wire_cost *= prefer_wire_unit; - return wire_cost; -} + std::vector> routing_segment_list; -double LayerAssigner::getEstimateViaCost(LAModel& la_model, LANode* start_node, LANode* end_node) -{ - double via_unit = la_model.get_la_com_param().get_via_unit(); - double via_cost = (via_unit * std::abs(start_node->get_layer_idx() - end_node->get_layer_idx())); - return via_cost; + std::queue*> pillar_node_queue = RTUTIL.initQueue(la_model.get_curr_la_task()->get_pillar_tree().get_root()); + while (!pillar_node_queue.empty()) { + TNode* parent_pillar_node = RTUTIL.getFrontAndPop(pillar_node_queue); + std::vector*>& child_list = parent_pillar_node->get_child_list(); + { + std::set layer_idx_set = parent_pillar_node->value().get_pin_layer_idx_set(); + layer_idx_set.insert(parent_pillar_node->value().get_layer_idx()); + for (TNode* child_node : child_list) { + layer_idx_set.insert(child_node->value().get_layer_idx()); + } + routing_segment_list.emplace_back(LayerCoord(parent_pillar_node->value().get_planar_coord(), *layer_idx_set.begin()), + LayerCoord(parent_pillar_node->value().get_planar_coord(), *layer_idx_set.rbegin())); + } + for (TNode* child_node : child_list) { + routing_segment_list.emplace_back(LayerCoord(parent_pillar_node->value().get_planar_coord(), child_node->value().get_layer_idx()), + LayerCoord(child_node->value().get_planar_coord(), child_node->value().get_layer_idx())); + } + RTUTIL.addListToQueue(pillar_node_queue, child_list); + } + return routing_segment_list; } MTree LayerAssigner::getCoordTree(LAModel& la_model, std::vector>& routing_segment_list) @@ -927,8 +778,8 @@ void LayerAssigner::updateSummary(LAModel& la_model) double& total_wire_length = summary.la_summary.total_wire_length; std::map& cut_via_num_map = summary.la_summary.cut_via_num_map; int32_t& total_via_num = summary.la_summary.total_via_num; - std::map>& clock_timing = summary.la_summary.clock_timing; - std::map& power_map = summary.la_summary.power_map; + std::map>& clock_timing_map = summary.la_summary.clock_timing_map; + std::map& type_power_map = summary.la_summary.type_power_map; std::vector>& layer_node_map = la_model.get_layer_node_map(); std::vector& la_net_list = la_model.get_la_net_list(); @@ -941,8 +792,8 @@ void LayerAssigner::updateSummary(LAModel& la_model) total_wire_length = 0; cut_via_num_map.clear(); total_via_num = 0; - clock_timing.clear(); - power_map.clear(); + clock_timing_map.clear(); + type_power_map.clear(); for (int32_t layer_idx = 0; layer_idx < static_cast(layer_node_map.size()); layer_idx++) { GridMap& la_node_map = layer_node_map[layer_idx]; @@ -1001,7 +852,7 @@ void LayerAssigner::updateSummary(LAModel& la_model) routing_segment_list_list[net_idx].emplace_back(first_real_coord, second_real_coord); } } - RTI.updateTimingAndPower(real_pin_coord_map_list, routing_segment_list_list, clock_timing, power_map); + RTI.updateTimingAndPower(real_pin_coord_map_list, routing_segment_list_list, clock_timing_map, type_power_map); } } @@ -1020,8 +871,8 @@ void LayerAssigner::printSummary(LAModel& la_model) double& total_wire_length = summary.la_summary.total_wire_length; std::map& cut_via_num_map = summary.la_summary.cut_via_num_map; int32_t& total_via_num = summary.la_summary.total_via_num; - std::map>& clock_timing = summary.la_summary.clock_timing; - std::map& power_map = summary.la_summary.power_map; + std::map>& clock_timing_map = summary.la_summary.clock_timing_map; + std::map& type_power_map = summary.la_summary.type_power_map; fort::char_table routing_demand_map_table; { @@ -1080,16 +931,16 @@ void LayerAssigner::printSummary(LAModel& la_model) << "tns" << "wns" << "freq" << fort::endr; - for (auto& [clock_name, timing_map] : clock_timing) { + for (auto& [clock_name, timing_map] : clock_timing_map) { timing_table << clock_name << timing_map["TNS"] << timing_map["WNS"] << timing_map["Freq(MHz)"] << fort::endr; } power_table << fort::header << "power_type"; - for (auto& [type, power] : power_map) { + for (auto& [type, power] : type_power_map) { power_table << fort::header << type; } power_table << fort::endr; power_table << "power_value"; - for (auto& [type, power] : power_map) { + for (auto& [type, power] : type_power_map) { power_table << power; } power_table << fort::endr; @@ -1219,54 +1070,64 @@ void LayerAssigner::outputOverflowCSV(LAModel& la_model) } } -void LayerAssigner::outputNetJson(LAModel& la_model) +void LayerAssigner::outputJson(LAModel& la_model) +{ + int32_t enable_notification = RTDM.getConfig().enable_notification; + if (!enable_notification) { + return; + } + std::map json_path_map; + json_path_map["net_map"] = outputNetJson(la_model); + json_path_map["overflow_map"] = outputOverflowJson(la_model); + json_path_map["summary"] = outputSummaryJson(la_model); + RTI.sendNotification("LA", 1, json_path_map); +} + +std::string LayerAssigner::outputNetJson(LAModel& la_model) { Die& die = RTDM.getDatabase().get_die(); ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& net_list = RTDM.getDatabase().get_net_list(); std::string& la_temp_directory_path = RTDM.getConfig().la_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector net_json_list; - net_json_list.resize(net_list.size()); - for (Net& net : net_list) { - net_json_list[net.get_net_idx()]["net_name"] = net.get_net_name(); - } - for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { - for (Segment* segment : segment_set) { - PlanarRect first_gcell = RTUTIL.getRealRectByGCell(segment->get_first(), gcell_axis); - PlanarRect second_gcell = RTUTIL.getRealRectByGCell(segment->get_second(), gcell_axis); - if (segment->get_first().get_layer_idx() != segment->get_second().get_layer_idx()) { - net_json_list[net_idx]["result"].push_back({first_gcell.get_ll_x(), first_gcell.get_ll_y(), first_gcell.get_ur_x(), first_gcell.get_ur_y(), - routing_layer_list[segment->get_first().get_layer_idx()].get_layer_name()}); - net_json_list[net_idx]["result"].push_back({second_gcell.get_ll_x(), second_gcell.get_ll_y(), second_gcell.get_ur_x(), second_gcell.get_ur_y(), - routing_layer_list[segment->get_second().get_layer_idx()].get_layer_name()}); - } else { - PlanarRect gcell = RTUTIL.getBoundingBox({first_gcell, second_gcell}); - net_json_list[net_idx]["result"].push_back({gcell.get_ll_x(), gcell.get_ll_y(), gcell.get_ur_x(), gcell.get_ur_y(), - routing_layer_list[segment->get_first().get_layer_idx()].get_layer_name()}); + { + nlohmann::json result_shape_json; + for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { + std::string net_name = net_list[net_idx].get_net_name(); + for (Segment* segment : segment_set) { + PlanarRect first_gcell = RTUTIL.getRealRectByGCell(segment->get_first(), gcell_axis); + PlanarRect second_gcell = RTUTIL.getRealRectByGCell(segment->get_second(), gcell_axis); + if (segment->get_first().get_layer_idx() != segment->get_second().get_layer_idx()) { + result_shape_json["result_shape"][net_name]["path"].push_back({first_gcell.get_ll_x(), first_gcell.get_ll_y(), first_gcell.get_ur_x(), + first_gcell.get_ur_y(), + routing_layer_list[segment->get_first().get_layer_idx()].get_layer_name()}); + result_shape_json["result_shape"][net_name]["path"].push_back({second_gcell.get_ll_x(), second_gcell.get_ll_y(), second_gcell.get_ur_x(), + second_gcell.get_ur_y(), + routing_layer_list[segment->get_second().get_layer_idx()].get_layer_name()}); + } else { + PlanarRect gcell = RTUTIL.getBoundingBox({first_gcell, second_gcell}); + result_shape_json["result_shape"][net_name]["path"].push_back({gcell.get_ll_x(), gcell.get_ll_y(), gcell.get_ur_x(), gcell.get_ur_y(), + routing_layer_list[segment->get_first().get_layer_idx()].get_layer_name()}); + } } } + net_json_list.push_back(result_shape_json); } std::string net_json_file_path = RTUTIL.getString(la_temp_directory_path, "net_map.json"); std::ofstream* net_json_file = RTUTIL.getOutputFileStream(net_json_file_path); (*net_json_file) << net_json_list; RTUTIL.closeFileStream(net_json_file); - RTI.sendNotification(RTUTIL.getString("LA_net_map"), net_json_file_path); + return net_json_file_path; } -void LayerAssigner::outputOverflowJson(LAModel& la_model) +std::string LayerAssigner::outputOverflowJson(LAModel& la_model) { ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::string& la_temp_directory_path = RTDM.getConfig().la_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector>& layer_node_map = la_model.get_layer_node_map(); std::vector overflow_json_list; for (int32_t layer_idx = 0; layer_idx < static_cast(layer_node_map.size()); layer_idx++) { @@ -1283,13 +1144,375 @@ void LayerAssigner::outputOverflowJson(LAModel& la_model) std::ofstream* overflow_json_file = RTUTIL.getOutputFileStream(overflow_json_file_path); (*overflow_json_file) << overflow_json_list; RTUTIL.closeFileStream(overflow_json_file); - RTI.sendNotification(RTUTIL.getString("LA_overflow_map"), overflow_json_file_path); + return overflow_json_file_path; +} + +std::string LayerAssigner::outputSummaryJson(LAModel& la_model) +{ + std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); + std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); + Summary& summary = RTDM.getDatabase().get_summary(); + std::string& la_temp_directory_path = RTDM.getConfig().la_temp_directory_path; + + std::map& routing_demand_map = summary.la_summary.routing_demand_map; + double& total_demand = summary.la_summary.total_demand; + std::map& routing_overflow_map = summary.la_summary.routing_overflow_map; + double& total_overflow = summary.la_summary.total_overflow; + std::map& routing_wire_length_map = summary.la_summary.routing_wire_length_map; + double& total_wire_length = summary.la_summary.total_wire_length; + std::map& cut_via_num_map = summary.la_summary.cut_via_num_map; + int32_t& total_via_num = summary.la_summary.total_via_num; + std::map>& clock_timing_map = summary.la_summary.clock_timing_map; + std::map& type_power_map = summary.la_summary.type_power_map; + + nlohmann::json summary_json; + for (auto& [routing_layer_idx, demand] : routing_demand_map) { + summary_json["routing_demand_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = demand; + } + summary_json["total_demand"] = total_demand; + for (auto& [routing_layer_idx, overflow] : routing_overflow_map) { + summary_json["routing_overflow_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = overflow; + } + summary_json["total_overflow"] = total_overflow; + for (auto& [routing_layer_idx, wire_length] : routing_wire_length_map) { + summary_json["routing_wire_length_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = wire_length; + } + summary_json["total_wire_length"] = total_wire_length; + for (auto& [cut_layer_idx, via_num] : cut_via_num_map) { + summary_json["cut_via_num_map"][cut_layer_list[cut_layer_idx].get_layer_name()] = via_num; + } + summary_json["total_via_num"] = total_via_num; + for (auto& [clock_name, timing] : clock_timing_map) { + summary_json["clock_timing_map"]["clock_name"] = clock_name; + summary_json["clock_timing_map"]["timing"] = timing; + } + for (auto& [type, power] : type_power_map) { + summary_json["type_power_map"]["type"] = type; + summary_json["type_power_map"]["power"] = power; + } + std::string summary_json_file_path = RTUTIL.getString(la_temp_directory_path, "summary.json"); + std::ofstream* summary_json_file = RTUTIL.getOutputFileStream(summary_json_file_path); + (*summary_json_file) << summary_json; + RTUTIL.closeFileStream(summary_json_file); + return summary_json_file_path; } #endif #if 1 // debug +void LayerAssigner::debugPlotLAModel(LAModel& la_model, std::string flag) +{ + ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); + Die& die = RTDM.getDatabase().get_die(); + std::string& la_temp_directory_path = RTDM.getConfig().la_temp_directory_path; + + int32_t point_size = 5; + + GPGDS gp_gds; + + // base_region + { + GPStruct base_region_struct("base_region"); + GPBoundary gp_boundary; + gp_boundary.set_layer_idx(0); + gp_boundary.set_data_type(0); + gp_boundary.set_rect(die.get_real_rect()); + base_region_struct.push(gp_boundary); + gp_gds.addStruct(base_region_struct); + } + + // gcell_axis + { + GPStruct gcell_axis_struct("gcell_axis"); + std::vector gcell_x_list = RTUTIL.getScaleList(die.get_real_ll_x(), die.get_real_ur_x(), gcell_axis.get_x_grid_list()); + std::vector gcell_y_list = RTUTIL.getScaleList(die.get_real_ll_y(), die.get_real_ur_y(), gcell_axis.get_y_grid_list()); + for (int32_t x : gcell_x_list) { + GPPath gp_path; + gp_path.set_layer_idx(0); + gp_path.set_data_type(1); + gp_path.set_segment(x, die.get_real_ll_y(), x, die.get_real_ur_y()); + gcell_axis_struct.push(gp_path); + } + for (int32_t y : gcell_y_list) { + GPPath gp_path; + gp_path.set_layer_idx(0); + gp_path.set_data_type(1); + gp_path.set_segment(die.get_real_ll_x(), y, die.get_real_ur_x(), y); + gcell_axis_struct.push(gp_path); + } + gp_gds.addStruct(gcell_axis_struct); + } + + // fixed_rect + for (auto& [is_routing, layer_net_rect_map] : RTDM.getTypeLayerNetFixedRectMap(die)) { + for (auto& [layer_idx, net_rect_map] : layer_net_rect_map) { + for (auto& [net_idx, rect_set] : net_rect_map) { + GPStruct fixed_rect_struct(RTUTIL.getString("fixed_rect(net_", net_idx, ")")); + for (EXTLayerRect* rect : rect_set) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kShape)); + gp_boundary.set_rect(rect->get_real_rect()); + if (is_routing) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(layer_idx)); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(layer_idx)); + } + fixed_rect_struct.push(gp_boundary); + } + gp_gds.addStruct(fixed_rect_struct); + } + } + } + + // access_point + for (auto& [net_idx, access_point_set] : RTDM.getNetAccessPointMap(die)) { + GPStruct access_point_struct(RTUTIL.getString("access_point(net_", net_idx, ")")); + for (AccessPoint* access_point : access_point_set) { + int32_t x = access_point->get_real_x(); + int32_t y = access_point->get_real_y(); + + GPBoundary access_point_boundary; + access_point_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(access_point->get_layer_idx())); + access_point_boundary.set_data_type(static_cast(GPDataType::kAccessPoint)); + access_point_boundary.set_rect(x - point_size, y - point_size, x + point_size, y + point_size); + access_point_struct.push(access_point_boundary); + } + gp_gds.addStruct(access_point_struct); + } + + // routing result + for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { + GPStruct global_result_struct(RTUTIL.getString("global_result(net_", net_idx, ")")); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetGlobalShapeList(net_idx, *segment)) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kGlobalPath)); + gp_boundary.set_rect(net_shape.get_rect()); + if (net_shape.get_is_routing()) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(net_shape.get_layer_idx())); + } + global_result_struct.push(gp_boundary); + } + } + gp_gds.addStruct(global_result_struct); + } + + // routing result + for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { + GPStruct detailed_result_struct(RTUTIL.getString("detailed_result(net_", net_idx, ")")); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kShape)); + gp_boundary.set_rect(net_shape.get_rect()); + if (net_shape.get_is_routing()) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(net_shape.get_layer_idx())); + } + detailed_result_struct.push(gp_boundary); + } + } + gp_gds.addStruct(detailed_result_struct); + } + + // routing patch + for (auto& [net_idx, patch_set] : RTDM.getNetDetailedPatchMap(die)) { + GPStruct detailed_patch_struct(RTUTIL.getString("detailed_patch(net_", net_idx, ")")); + for (EXTLayerRect* patch : patch_set) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kShape)); + gp_boundary.set_rect(patch->get_real_rect()); + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(patch->get_layer_idx())); + detailed_patch_struct.push(gp_boundary); + } + gp_gds.addStruct(detailed_patch_struct); + } + + // layer_node_map + { + std::vector>& layer_node_map = la_model.get_layer_node_map(); + // la_node_map + { + GPStruct la_node_map_struct("la_node_map"); + for (GridMap& la_node_map : layer_node_map) { + for (int32_t grid_x = 0; grid_x < la_node_map.get_x_size(); grid_x++) { + for (int32_t grid_y = 0; grid_y < la_node_map.get_y_size(); grid_y++) { + LANode& la_node = la_node_map[grid_x][grid_y]; + PlanarRect real_rect = RTUTIL.getRealRectByGCell(la_node.get_planar_coord(), gcell_axis); + int32_t y_reduced_span = std::max(1, real_rect.getYSpan() / 12); + int32_t y = real_rect.get_ur_y(); + + y -= y_reduced_span; + GPText gp_text_node_real_coord; + gp_text_node_real_coord.set_coord(real_rect.get_ll_x(), y); + gp_text_node_real_coord.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_node_real_coord.set_message(RTUTIL.getString("(", la_node.get_x(), " , ", la_node.get_y(), " , ", la_node.get_layer_idx(), ")")); + gp_text_node_real_coord.set_layer_idx(RTGP.getGDSIdxByRouting(la_node.get_layer_idx())); + gp_text_node_real_coord.set_presentation(GPTextPresentation::kLeftMiddle); + la_node_map_struct.push(gp_text_node_real_coord); + + y -= y_reduced_span; + GPText gp_text_node_grid_coord; + gp_text_node_grid_coord.set_coord(real_rect.get_ll_x(), y); + gp_text_node_grid_coord.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_node_grid_coord.set_message(RTUTIL.getString("(", grid_x, " , ", grid_y, " , ", la_node.get_layer_idx(), ")")); + gp_text_node_grid_coord.set_layer_idx(RTGP.getGDSIdxByRouting(la_node.get_layer_idx())); + gp_text_node_grid_coord.set_presentation(GPTextPresentation::kLeftMiddle); + la_node_map_struct.push(gp_text_node_grid_coord); + + y -= y_reduced_span; + GPText gp_text_orient_supply_map; + gp_text_orient_supply_map.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_supply_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_orient_supply_map.set_message("orient_supply_map: "); + gp_text_orient_supply_map.set_layer_idx(RTGP.getGDSIdxByRouting(la_node.get_layer_idx())); + gp_text_orient_supply_map.set_presentation(GPTextPresentation::kLeftMiddle); + la_node_map_struct.push(gp_text_orient_supply_map); + + if (!la_node.get_orient_supply_map().empty()) { + y -= y_reduced_span; + GPText gp_text_orient_supply_map_info; + gp_text_orient_supply_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_supply_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string orient_supply_map_info_message = "--"; + for (auto& [orient, supply] : la_node.get_orient_supply_map()) { + orient_supply_map_info_message += RTUTIL.getString("(", GetOrientationName()(orient), ",", supply, ")"); + } + gp_text_orient_supply_map_info.set_message(orient_supply_map_info_message); + gp_text_orient_supply_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(la_node.get_layer_idx())); + gp_text_orient_supply_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + la_node_map_struct.push(gp_text_orient_supply_map_info); + } + + y -= y_reduced_span; + GPText gp_text_ignore_net_orient_map; + gp_text_ignore_net_orient_map.set_coord(real_rect.get_ll_x(), y); + gp_text_ignore_net_orient_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_ignore_net_orient_map.set_message("ignore_net_orient_map: "); + gp_text_ignore_net_orient_map.set_layer_idx(RTGP.getGDSIdxByRouting(la_node.get_layer_idx())); + gp_text_ignore_net_orient_map.set_presentation(GPTextPresentation::kLeftMiddle); + la_node_map_struct.push(gp_text_ignore_net_orient_map); + + if (!la_node.get_ignore_net_orient_map().empty()) { + y -= y_reduced_span; + GPText gp_text_ignore_net_orient_map_info; + gp_text_ignore_net_orient_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_ignore_net_orient_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string ignore_net_orient_map_info_message = "--"; + for (auto& [net_idx, orient_set] : la_node.get_ignore_net_orient_map()) { + ignore_net_orient_map_info_message += RTUTIL.getString("(", net_idx); + for (Orientation orient : orient_set) { + ignore_net_orient_map_info_message += RTUTIL.getString(",", GetOrientationName()(orient)); + } + ignore_net_orient_map_info_message += RTUTIL.getString(")"); + } + gp_text_ignore_net_orient_map_info.set_message(ignore_net_orient_map_info_message); + gp_text_ignore_net_orient_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(la_node.get_layer_idx())); + gp_text_ignore_net_orient_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + la_node_map_struct.push(gp_text_ignore_net_orient_map_info); + } + + y -= y_reduced_span; + GPText gp_text_orient_net_map; + gp_text_orient_net_map.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_net_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_orient_net_map.set_message("orient_net_map: "); + gp_text_orient_net_map.set_layer_idx(RTGP.getGDSIdxByRouting(la_node.get_layer_idx())); + gp_text_orient_net_map.set_presentation(GPTextPresentation::kLeftMiddle); + la_node_map_struct.push(gp_text_orient_net_map); + + if (!la_node.get_orient_net_map().empty()) { + y -= y_reduced_span; + GPText gp_text_orient_net_map_info; + gp_text_orient_net_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_net_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string orient_net_map_info_message = "--"; + for (auto& [orient, net_set] : la_node.get_orient_net_map()) { + orient_net_map_info_message += RTUTIL.getString("(", GetOrientationName()(orient)); + for (int32_t net_idx : net_set) { + orient_net_map_info_message += RTUTIL.getString(",", net_idx); + } + orient_net_map_info_message += RTUTIL.getString(")"); + } + gp_text_orient_net_map_info.set_message(orient_net_map_info_message); + gp_text_orient_net_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(la_node.get_layer_idx())); + gp_text_orient_net_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + la_node_map_struct.push(gp_text_orient_net_map_info); + } + + y -= y_reduced_span; + GPText gp_text_net_orient_map; + gp_text_net_orient_map.set_coord(real_rect.get_ll_x(), y); + gp_text_net_orient_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_net_orient_map.set_message("net_orient_map: "); + gp_text_net_orient_map.set_layer_idx(RTGP.getGDSIdxByRouting(la_node.get_layer_idx())); + gp_text_net_orient_map.set_presentation(GPTextPresentation::kLeftMiddle); + la_node_map_struct.push(gp_text_net_orient_map); + + if (!la_node.get_net_orient_map().empty()) { + y -= y_reduced_span; + GPText gp_text_net_orient_map_info; + gp_text_net_orient_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_net_orient_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string net_orient_map_info_message = "--"; + for (auto& [net_idx, orient_set] : la_node.get_net_orient_map()) { + net_orient_map_info_message += RTUTIL.getString("(", net_idx); + for (Orientation orient : orient_set) { + net_orient_map_info_message += RTUTIL.getString(",", GetOrientationName()(orient)); + } + net_orient_map_info_message += RTUTIL.getString(")"); + } + gp_text_net_orient_map_info.set_message(net_orient_map_info_message); + gp_text_net_orient_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(la_node.get_layer_idx())); + gp_text_net_orient_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + la_node_map_struct.push(gp_text_net_orient_map_info); + } + + y -= y_reduced_span; + GPText gp_text_overflow; + gp_text_overflow.set_coord(real_rect.get_ll_x(), y); + gp_text_overflow.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_overflow.set_message(RTUTIL.getString("overflow: ", la_node.getOverflow())); + gp_text_overflow.set_layer_idx(RTGP.getGDSIdxByRouting(la_node.get_layer_idx())); + gp_text_overflow.set_presentation(GPTextPresentation::kLeftMiddle); + la_node_map_struct.push(gp_text_overflow); + } + } + } + gp_gds.addStruct(la_node_map_struct); + } + // overflow + { + GPStruct overflow_struct("overflow"); + for (GridMap& la_node_map : layer_node_map) { + for (int32_t grid_x = 0; grid_x < la_node_map.get_x_size(); grid_x++) { + for (int32_t grid_y = 0; grid_y < la_node_map.get_y_size(); grid_y++) { + LANode& la_node = la_node_map[grid_x][grid_y]; + if (la_node.getOverflow() <= 0) { + continue; + } + PlanarRect real_rect = RTUTIL.getRealRectByGCell(la_node.get_planar_coord(), gcell_axis); + + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kOverflow)); + gp_boundary.set_rect(real_rect); + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(la_node.get_layer_idx())); + overflow_struct.push(gp_boundary); + } + } + } + gp_gds.addStruct(overflow_struct); + } + } + + std::string gds_file_path = RTUTIL.getString(la_temp_directory_path, flag, "_la_model.gds"); + RTGP.plot(gp_gds, gds_file_path); +} + void LayerAssigner::debugCheckLAModel(LAModel& la_model) { std::vector>& layer_node_map = la_model.get_layer_node_map(); diff --git a/src/operation/iRT/source/module/layer_assigner/LayerAssigner.hpp b/src/operation/iRT/source/module/layer_assigner/LayerAssigner.hpp index 6745047b51f268b3867bf391d35c060ce411cb32..543b8a245bfcdb4f1638ea2ef2c604bfc835d374 100644 --- a/src/operation/iRT/source/module/layer_assigner/LayerAssigner.hpp +++ b/src/operation/iRT/source/module/layer_assigner/LayerAssigner.hpp @@ -21,6 +21,7 @@ #include "DataManager.hpp" #include "Database.hpp" #include "LAModel.hpp" +#include "LAPackage.hpp" #include "RTHeader.hpp" namespace irt { @@ -55,36 +56,29 @@ class LayerAssigner void buildLayerNodeMap(LAModel& la_model); void buildLANodeNeighbor(LAModel& la_model); void buildOrientSupply(LAModel& la_model); - void buildTopoTree(LAModel& la_model); + void buildPlaneTree(LAModel& la_model); void routeLAModel(LAModel& la_model); - void routeLATask(LAModel& la_model, LANet* la_net); + void routeLATask(LAModel& la_model, LANet* la_task); void initSingleTask(LAModel& la_model, LANet* la_task); - void makeLATopoList(LAModel& la_model, std::vector& la_topo_list, std::vector>& routing_segment_list); - void routeLATopo(LAModel& la_model, LATopo* la_topo); - void initSingleTopo(LAModel& la_model, LATopo* la_topo); - bool isConnectedAllEnd(LAModel& la_model); - void routeSinglePath(LAModel& la_model); - void initPathHead(LAModel& la_model); - bool searchEnded(LAModel& la_model); - void expandSearching(LAModel& la_model); - void resetPathHead(LAModel& la_model); - void updatePathResult(LAModel& la_model); - std::vector> getRoutingSegmentListByNode(LANode* node); - void resetStartAndEnd(LAModel& la_model); - void resetSinglePath(LAModel& la_model); - void updateTopoResult(LAModel& la_model); + bool needRouting(LAModel& la_model); + void spiltPlaneTree(LAModel& la_model); + void insertMidPoint(LAModel& la_model, TNode* planar_node, TNode* child_node); + void buildPillarTree(LAModel& la_model); + LAPillar convertLAPillar(LayerCoord& layer_coord, std::map, CmpPlanarCoordByXASC>& coord_pin_layer_map); + void assignPillarTree(LAModel& la_model); + void assignForward(LAModel& la_model); + std::vector getCandidateLayerList(LAModel& la_model, LAPackage& la_package); + double getFullViaCost(LAModel& la_model, std::set& layer_idx_set, int32_t candidate_layer_idx); + void buildLayerCost(LAModel& la_model, LAPackage& la_package); + std::pair getParentPillarCost(LAModel& la_model, LAPackage& la_package, int32_t candidate_layer_idx); + double getExtraViaCost(LAModel& la_model, std::set& layer_idx_set, int32_t candidate_layer_idx); + double getSegmentCost(LAModel& la_model, LAPackage& la_package, int32_t candidate_layer_idx); + double getChildPillarCost(LAModel& la_model, LAPackage& la_package, int32_t candidate_layer_idx); + void assignBackward(LAModel& la_model); + int32_t getBestLayerBySelf(TNode* pillar_node); + int32_t getBestLayerByChild(TNode* parent_pillar_node); + void buildLayerTree(LAModel& la_model); std::vector> getRoutingSegmentList(LAModel& la_model); - void resetSingleTopo(LAModel& la_model); - void pushToOpenList(LAModel& la_model, LANode* curr_node); - LANode* popFromOpenList(LAModel& la_model); - double getKnownCost(LAModel& la_model, LANode* start_node, LANode* end_node); - double getNodeCost(LAModel& la_model, LANode* curr_node, Orientation orientation); - double getKnownWireCost(LAModel& la_model, LANode* start_node, LANode* end_node); - double getKnownViaCost(LAModel& la_model, LANode* start_node, LANode* end_node); - double getEstimateCostToEnd(LAModel& la_model, LANode* curr_node); - double getEstimateCost(LAModel& la_model, LANode* start_node, LANode* end_node); - double getEstimateWireCost(LAModel& la_model, LANode* start_node, LANode* end_node); - double getEstimateViaCost(LAModel& la_model, LANode* start_node, LANode* end_node); MTree getCoordTree(LAModel& la_model, std::vector>& routing_segment_list); void uploadNetResult(LAModel& la_model, MTree& coord_tree); void resetSingleTask(LAModel& la_model); @@ -99,11 +93,14 @@ class LayerAssigner void outputGuide(LAModel& la_model); void outputNetCSV(LAModel& la_model); void outputOverflowCSV(LAModel& la_model); - void outputNetJson(LAModel& la_model); - void outputOverflowJson(LAModel& la_model); + void outputJson(LAModel& la_model); + std::string outputNetJson(LAModel& la_model); + std::string outputOverflowJson(LAModel& la_model); + std::string outputSummaryJson(LAModel& la_model); #endif #if 1 // debug + void debugPlotLAModel(LAModel& la_model, std::string flag); void debugCheckLAModel(LAModel& la_model); #endif }; diff --git a/src/operation/iRT/source/module/layer_assigner/framwork.txt b/src/operation/iRT/source/module/layer_assigner/framwork.txt index afd802155a243117939075e7b52e28fe14a1d9b2..dfc2ed083ecd6e84fc1f6ab5ddd4be3a1f9b49e3 100644 --- a/src/operation/iRT/source/module/layer_assigner/framwork.txt +++ b/src/operation/iRT/source/module/layer_assigner/framwork.txt @@ -1,10 +1,9 @@ initLAModel:初始化la_net_list setLAComParam:设置布线参数 -initLATaskList:构建task,有序 +initLATaskList:构建task,有序 buildLayerNodeMap:初始化graph buildLANodeNeighbor:构建graph的邻居 buildOrientSupply:从supply_analyzer获取supply的access -buildTopoTree:从顶层拿取topo树 +buildPlaneTree:从顶层拿取topo树 routeLAModel: - routeLATask:一个接一个的la_net进行布线 -updateLAModel:将结果更新到顶层 \ No newline at end of file + routeLATask:一个接一个的la_net进行布线 \ No newline at end of file diff --git a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAComParam.hpp b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAComParam.hpp index e39ef4ae80db78eb5a85327713b0b9dcfac7a471..af5634d17be24c2f86c74b7317ce4aafb6b4b2b6 100644 --- a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAComParam.hpp +++ b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAComParam.hpp @@ -22,28 +22,24 @@ class LAComParam { public: LAComParam() = default; - LAComParam(int32_t topo_spilt_length, double prefer_wire_unit, double via_unit, double overflow_unit) + LAComParam(int32_t topo_spilt_length, double via_unit, double overflow_unit) { _topo_spilt_length = topo_spilt_length; - _prefer_wire_unit = prefer_wire_unit; _via_unit = via_unit; _overflow_unit = overflow_unit; } ~LAComParam() = default; // getter int32_t get_topo_spilt_length() const { return _topo_spilt_length; } - double get_prefer_wire_unit() const { return _prefer_wire_unit; } double get_via_unit() const { return _via_unit; } double get_overflow_unit() const { return _overflow_unit; } // setter void set_topo_spilt_length(const int32_t topo_spilt_length) { _topo_spilt_length = topo_spilt_length; } - void set_prefer_wire_unit(const double prefer_wire_unit) { _prefer_wire_unit = prefer_wire_unit; } void set_via_unit(const double via_unit) { _via_unit = via_unit; } void set_overflow_unit(const double overflow_unit) { _overflow_unit = overflow_unit; } private: int32_t _topo_spilt_length = 0; - double _prefer_wire_unit = 0; double _via_unit = 0; double _overflow_unit = 0; }; diff --git a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LALayerCost.hpp b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LALayerCost.hpp new file mode 100644 index 0000000000000000000000000000000000000000..66f92424f14ea1db348634c1bb700e3be13225c0 --- /dev/null +++ b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LALayerCost.hpp @@ -0,0 +1,44 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once + +#include "RTHeader.hpp" + +namespace irt { + +class LALayerCost +{ + public: + LALayerCost() = default; + ~LALayerCost() = default; + // getter + int32_t get_parent_layer_idx() const { return _parent_layer_idx; } + int32_t get_layer_idx() const { return _layer_idx; } + double get_history_cost() const { return _history_cost; } + // setter + void set_parent_layer_idx(const int32_t parent_layer_idx) { _parent_layer_idx = parent_layer_idx; } + void set_layer_idx(const int32_t layer_idx) { _layer_idx = layer_idx; } + void set_history_cost(const double history_cost) { _history_cost = history_cost; } + // function + + private: + int32_t _parent_layer_idx = -1; + int32_t _layer_idx = -1; + double _history_cost = 0; +}; + +} // namespace irt diff --git a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAModel.hpp b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAModel.hpp index c1383f41319a311197948debb5d8c576cc344b90..5e8d11e1f71a0e296a2cc5d836e229a3aaf11a53 100644 --- a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAModel.hpp +++ b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAModel.hpp @@ -19,7 +19,6 @@ #include "LAComParam.hpp" #include "LANet.hpp" #include "LANode.hpp" -#include "LATopo.hpp" #include "PriorityQueue.hpp" namespace irt { @@ -46,36 +45,6 @@ class LAModel LANet* get_curr_la_task() { return _curr_la_task; } void set_curr_la_task(LANet* curr_la_task) { _curr_la_task = curr_la_task; } #endif -#if 1 // astar - // single topo - LATopo* get_curr_la_topo() { return _curr_la_topo; } - std::vector>& get_start_node_list_list() { return _start_node_list_list; } - std::vector>& get_end_node_list_list() { return _end_node_list_list; } - std::vector& get_path_node_list() { return _path_node_list; } - std::vector& get_single_topo_visited_node_list() { return _single_topo_visited_node_list; } - std::vector>& get_routing_segment_list() { return _routing_segment_list; } - void set_curr_la_topo(LATopo* curr_la_topo) { _curr_la_topo = curr_la_topo; } - void set_start_node_list_list(const std::vector>& start_node_list_list) { _start_node_list_list = start_node_list_list; } - void set_end_node_list_list(const std::vector>& end_node_list_list) { _end_node_list_list = end_node_list_list; } - void set_path_node_list(const std::vector& path_node_list) { _path_node_list = path_node_list; } - void set_single_topo_visited_node_list(const std::vector& single_topo_visited_node_list) - { - _single_topo_visited_node_list = single_topo_visited_node_list; - } - void set_routing_segment_list(const std::vector>& routing_segment_list) { _routing_segment_list = routing_segment_list; } - // single path - PriorityQueue, CmpLANodeCost>& get_open_queue() { return _open_queue; } - std::vector& get_single_path_visited_node_list() { return _single_path_visited_node_list; } - LANode* get_path_head_node() { return _path_head_node; } - int32_t get_end_node_list_idx() const { return _end_node_list_idx; } - void set_open_queue(const PriorityQueue, CmpLANodeCost>& open_queue) { _open_queue = open_queue; } - void set_single_path_visited_node_list(const std::vector& single_path_visited_node_list) - { - _single_path_visited_node_list = single_path_visited_node_list; - } - void set_path_head_node(LANode* path_head_node) { _path_head_node = path_head_node; } - void set_end_node_list_idx(const int32_t end_node_list_idx) { _end_node_list_idx = end_node_list_idx; } -#endif private: std::vector _la_net_list; @@ -86,20 +55,6 @@ class LAModel // single task LANet* _curr_la_task = nullptr; #endif -#if 1 // astar - // single topo - LATopo* _curr_la_topo = nullptr; - std::vector> _start_node_list_list; - std::vector> _end_node_list_list; - std::vector _path_node_list; - std::vector _single_topo_visited_node_list; - std::vector> _routing_segment_list; - // single path - PriorityQueue, CmpLANodeCost> _open_queue; - std::vector _single_path_visited_node_list; - LANode* _path_head_node = nullptr; - int32_t _end_node_list_idx = -1; -#endif }; } // namespace irt diff --git a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LANet.hpp b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LANet.hpp index 6a5cabc35e2225d1174f8faa5b48714454e7532b..5ed1343fcd0e85884ac2eb12176545aab5403ea6 100644 --- a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LANet.hpp +++ b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LANet.hpp @@ -16,6 +16,7 @@ // *************************************************************************************** #pragma once +#include "LAPillar.hpp" #include "LAPin.hpp" #include "Net.hpp" @@ -32,7 +33,8 @@ class LANet ConnectType& get_connect_type() { return _connect_type; } std::vector& get_la_pin_list() { return _la_pin_list; } BoundingBox& get_bounding_box() { return _bounding_box; } - MTree& get_topo_tree() { return _topo_tree; } + MTree& get_planar_tree() { return _planar_tree; } + MTree& get_pillar_tree() { return _pillar_tree; } // const getter const ConnectType& get_connect_type() const { return _connect_type; } const std::vector& get_la_pin_list() const { return _la_pin_list; } @@ -43,7 +45,8 @@ class LANet void set_connect_type(const ConnectType& connect_type) { _connect_type = connect_type; } void set_la_pin_list(const std::vector& la_pin_list) { _la_pin_list = la_pin_list; } void set_bounding_box(const BoundingBox& bounding_box) { _bounding_box = bounding_box; } - void set_topo_tree(const MTree& topo_tree) { _topo_tree = topo_tree; } + void set_planar_tree(const MTree& planar_tree) { _planar_tree = planar_tree; } + void set_pillar_tree(const MTree& pillar_tree) { _pillar_tree = pillar_tree; } // function private: @@ -52,7 +55,8 @@ class LANet ConnectType _connect_type = ConnectType::kNone; std::vector _la_pin_list; BoundingBox _bounding_box; - MTree _topo_tree; + MTree _planar_tree; + MTree _pillar_tree; }; struct CmpLANet diff --git a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LANode.hpp b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LANode.hpp index d61461c2c98fe3d0f087c92c29f8ad0451adede4..ded3f0d55eee1fa52c3c7a69686f67707d56ce9c 100644 --- a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LANode.hpp +++ b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LANode.hpp @@ -24,15 +24,6 @@ namespace irt { -#if 1 // astar -enum class LANodeState -{ - kNone = 0, - kOpen = 1, - kClose = 2 -}; -#endif - class LANode : public LayerCoord { public: @@ -44,6 +35,7 @@ class LANode : public LayerCoord double get_internal_via_unit() const { return _internal_via_unit; } std::map& get_neighbor_node_map() { return _neighbor_node_map; } std::map& get_orient_supply_map() { return _orient_supply_map; } + std::map>& get_ignore_net_orient_map() { return _ignore_net_orient_map; } std::map>& get_orient_net_map() { return _orient_net_map; } std::map>& get_net_orient_map() { return _net_orient_map; } // setter @@ -52,6 +44,7 @@ class LANode : public LayerCoord void set_internal_via_unit(const double internal_via_unit) { _internal_via_unit = internal_via_unit; } void set_neighbor_node_map(const std::map& neighbor_node_map) { _neighbor_node_map = neighbor_node_map; } void set_orient_supply_map(const std::map& orient_supply_map) { _orient_supply_map = orient_supply_map; } + void set_ignore_net_orient_map(const std::map>& ignore_net_orient_map) { _ignore_net_orient_map = ignore_net_orient_map; } void set_orient_net_map(const std::map>& orient_net_map) { _orient_net_map = orient_net_map; } void set_net_orient_map(const std::map>& net_orient_map) { _net_orient_map = net_orient_map; } // function @@ -63,41 +56,63 @@ class LANode : public LayerCoord } return neighbor_node; } - double getOverflowCost(int32_t curr_net_idx, Orientation orientation, double overflow_unit) + double getOverflowCost(int32_t net_idx, Direction direction, double overflow_unit) { if (!validDemandUnit()) { RTLOG.error(Loc::current(), "The demand unit is error!"); } + std::map> orient_net_map = _orient_net_map; + std::map> net_orient_map = _net_orient_map; + if (direction == Direction::kHorizontal) { + for (Orientation orient : {Orientation::kEast, Orientation::kWest}) { + orient_net_map[orient].insert(net_idx); + net_orient_map[net_idx].insert(orient); + } + } else if (direction == Direction::kVertical) { + for (Orientation orient : {Orientation::kSouth, Orientation::kNorth}) { + orient_net_map[orient].insert(net_idx); + net_orient_map[net_idx].insert(orient); + } + } else { + RTLOG.error(Loc::current(), "The direction is error!"); + } double boundary_overflow = 0; - if (orientation == Orientation::kEast || orientation == Orientation::kWest || orientation == Orientation::kSouth || orientation == Orientation::kNorth) { + for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { double boundary_demand = 0; - if (RTUTIL.exist(_orient_net_map, orientation)) { - std::set& net_set = _orient_net_map[orientation]; - boundary_demand += (static_cast(net_set.size()) * _boundary_wire_unit); - if (RTUTIL.exist(net_set, curr_net_idx)) { - boundary_demand -= _boundary_wire_unit; + if (RTUTIL.exist(orient_net_map, orient)) { + for (int32_t demand_net_idx : orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + boundary_demand += _boundary_wire_unit; } } double boundary_supply = 0; - if (RTUTIL.exist(_orient_supply_map, orientation)) { - boundary_supply = (_orient_supply_map[orientation] * _boundary_wire_unit); + if (RTUTIL.exist(_orient_supply_map, orient)) { + boundary_supply = (_orient_supply_map[orient] * _boundary_wire_unit); } - boundary_overflow = calcCost(boundary_demand + _boundary_wire_unit, boundary_supply); + boundary_overflow += calcCost(boundary_demand, boundary_supply); } double internal_overflow = 0; { double internal_demand = 0; - for (auto& [orient, net_set] : _orient_net_map) { - if (orient == Orientation::kAbove || orient == Orientation::kBelow) { - continue; - } - internal_demand += (static_cast(net_set.size()) * _internal_wire_unit); - if (RTUTIL.exist(net_set, curr_net_idx)) { - internal_demand -= _internal_wire_unit; + for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { + if (RTUTIL.exist(orient_net_map, orient)) { + for (int32_t demand_net_idx : orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + internal_demand += _internal_wire_unit; + } } } - for (auto& [net_idx, orient_set] : _net_orient_map) { - if (net_idx == curr_net_idx) { + for (auto& [net_idx, orient_set] : net_orient_map) { + if (RTUTIL.exist(_ignore_net_orient_map, net_idx) + && (RTUTIL.exist(_ignore_net_orient_map[net_idx], Orientation::kAbove) || RTUTIL.exist(_ignore_net_orient_map[net_idx], Orientation::kBelow))) { + continue; + } + if (RTUTIL.exist(orient_set, Orientation::kEast) || RTUTIL.exist(orient_set, Orientation::kWest) || RTUTIL.exist(orient_set, Orientation::kSouth) + || RTUTIL.exist(orient_set, Orientation::kNorth)) { continue; } if (RTUTIL.exist(orient_set, Orientation::kAbove) || RTUTIL.exist(orient_set, Orientation::kBelow)) { @@ -108,11 +123,7 @@ class LANode : public LayerCoord for (auto& [orient, supply] : _orient_supply_map) { internal_supply += (supply * _internal_wire_unit); } - if (orientation == Orientation::kEast || orientation == Orientation::kWest || orientation == Orientation::kSouth || orientation == Orientation::kNorth) { - internal_overflow = calcCost(internal_demand + _internal_wire_unit, internal_supply); - } else if (orientation == Orientation::kAbove || orientation == Orientation::kBelow) { - internal_overflow = calcCost(internal_demand + _internal_via_unit, internal_supply); - } + internal_overflow += calcCost(internal_demand, internal_supply); } double cost = 0; cost += (overflow_unit * (boundary_overflow + internal_overflow)); @@ -137,9 +148,9 @@ class LANode : public LayerCoord if (demand == supply) { cost = 1; } else if (demand > supply) { - cost = std::pow(demand - supply + 1, 2); + cost = std::pow(demand - supply + 1, 4); } else if (demand < supply) { - cost = std::pow(demand / supply, 2); + cost = std::pow(demand / supply, 4); } return cost; } @@ -161,6 +172,10 @@ class LANode : public LayerCoord } } for (auto& [net_idx, orient_set] : _net_orient_map) { + if (RTUTIL.exist(orient_set, Orientation::kEast) || RTUTIL.exist(orient_set, Orientation::kWest) || RTUTIL.exist(orient_set, Orientation::kSouth) + || RTUTIL.exist(orient_set, Orientation::kNorth)) { + continue; + } if (RTUTIL.exist(orient_set, Orientation::kAbove) || RTUTIL.exist(orient_set, Orientation::kBelow)) { internal_demand += _internal_via_unit; } @@ -176,7 +191,12 @@ class LANode : public LayerCoord for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { double boundary_demand = 0; if (RTUTIL.exist(_orient_net_map, orient)) { - boundary_demand = (static_cast(_orient_net_map[orient].size()) * _boundary_wire_unit); + for (int32_t demand_net_idx : _orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + boundary_demand += _boundary_wire_unit; + } } double boundary_supply = 0; if (RTUTIL.exist(_orient_supply_map, orient)) { @@ -189,10 +209,23 @@ class LANode : public LayerCoord double internal_demand = 0; for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { if (RTUTIL.exist(_orient_net_map, orient)) { - internal_demand += (static_cast(_orient_net_map[orient].size()) * _internal_wire_unit); + for (int32_t demand_net_idx : _orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + internal_demand += _internal_wire_unit; + } } } for (auto& [net_idx, orient_set] : _net_orient_map) { + if (RTUTIL.exist(_ignore_net_orient_map, net_idx) + && (RTUTIL.exist(_ignore_net_orient_map[net_idx], Orientation::kAbove) || RTUTIL.exist(_ignore_net_orient_map[net_idx], Orientation::kBelow))) { + continue; + } + if (RTUTIL.exist(orient_set, Orientation::kEast) || RTUTIL.exist(orient_set, Orientation::kWest) || RTUTIL.exist(orient_set, Orientation::kSouth) + || RTUTIL.exist(orient_set, Orientation::kNorth)) { + continue; + } if (RTUTIL.exist(orient_set, Orientation::kAbove) || RTUTIL.exist(orient_set, Orientation::kBelow)) { internal_demand += _internal_via_unit; } @@ -213,26 +246,16 @@ class LANode : public LayerCoord _net_orient_map[net_idx].insert(orient); } else { _orient_net_map[orient].erase(net_idx); + if (_orient_net_map[orient].empty()) { + _orient_net_map.erase(orient); + } _net_orient_map[net_idx].erase(orient); + if (_net_orient_map[net_idx].empty()) { + _net_orient_map.erase(net_idx); + } } } } -#if 1 // astar - // single path - LANodeState& get_state() { return _state; } - LANode* get_parent_node() const { return _parent_node; } - double get_known_cost() const { return _known_cost; } - double get_estimated_cost() const { return _estimated_cost; } - void set_state(LANodeState state) { _state = state; } - void set_parent_node(LANode* parent_node) { _parent_node = parent_node; } - void set_known_cost(const double known_cost) { _known_cost = known_cost; } - void set_estimated_cost(const double estimated_cost) { _estimated_cost = estimated_cost; } - // function - bool isNone() { return _state == LANodeState::kNone; } - bool isOpen() { return _state == LANodeState::kOpen; } - bool isClose() { return _state == LANodeState::kClose; } - double getTotalCost() { return (_known_cost + _estimated_cost); } -#endif private: double _boundary_wire_unit = -1; @@ -240,33 +263,9 @@ class LANode : public LayerCoord double _internal_via_unit = -1; std::map _neighbor_node_map; std::map _orient_supply_map; + std::map> _ignore_net_orient_map; std::map> _orient_net_map; std::map> _net_orient_map; -#if 1 // astar - // single path - LANodeState _state = LANodeState::kNone; - LANode* _parent_node = nullptr; - double _known_cost = 0.0; // include curr - double _estimated_cost = 0.0; -#endif -}; - -#if 1 // astar -struct CmpLANodeCost -{ - bool operator()(LANode* a, LANode* b) - { - if (RTUTIL.equalDoubleByError(a->getTotalCost(), b->getTotalCost(), RT_ERROR)) { - if (RTUTIL.equalDoubleByError(a->get_estimated_cost(), b->get_estimated_cost(), RT_ERROR)) { - return a->get_neighbor_node_map().size() < b->get_neighbor_node_map().size(); - } else { - return a->get_estimated_cost() > b->get_estimated_cost(); - } - } else { - return a->getTotalCost() > b->getTotalCost(); - } - } }; -#endif } // namespace irt diff --git a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAPackage.hpp b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAPackage.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b4234fa642613b0a9c2f30a25c9a366ebfd54764 --- /dev/null +++ b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAPackage.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "LAPillar.hpp" +#include "TNode.hpp" + +namespace irt { + +class LAPackage +{ + public: + LAPackage() = default; + explicit LAPackage(TNode* parent_pillar_node, TNode* child_pillar_node) + { + _parent_pillar_node = parent_pillar_node; + _child_pillar_node = child_pillar_node; + } + ~LAPackage() = default; + // getter + TNode* get_parent_pillar_node() { return _parent_pillar_node; } + TNode* get_child_pillar_node() { return _child_pillar_node; } + // const getter + const TNode* get_parent_pillar_node() const { return _parent_pillar_node; } + const TNode* get_child_pillar_node() const { return _child_pillar_node; } + // setter + void set_parent_pillar_node(TNode* parent_pillar_node) { _parent_pillar_node = parent_pillar_node; } + void set_child_pillar_node(TNode* child_pillar_node) { _child_pillar_node = child_pillar_node; } + // function + LAPillar& getParentPillar() { return _parent_pillar_node->value(); } + LAPillar& getChildPillar() { return _child_pillar_node->value(); } + + private: + TNode* _parent_pillar_node = nullptr; + TNode* _child_pillar_node = nullptr; +}; + +} // namespace irt diff --git a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAPillar.hpp b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAPillar.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9049b466d89fda6b662504f720177764639e16e9 --- /dev/null +++ b/src/operation/iRT/source/module/layer_assigner/la_data_manager/LAPillar.hpp @@ -0,0 +1,47 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once + +#include "LALayerCost.hpp" +#include "PlanarCoord.hpp" + +namespace irt { + +class LAPillar +{ + public: + LAPillar() = default; + ~LAPillar() = default; + // getter + PlanarCoord& get_planar_coord() { return _planar_coord; } + std::set& get_pin_layer_idx_set() { return _pin_layer_idx_set; } + std::vector& get_layer_cost_list() { return _layer_cost_list; } + int32_t get_layer_idx() const { return _layer_idx; } + // setter + void set_planar_coord(const PlanarCoord& planar_coord) { _planar_coord = planar_coord; } + void set_pin_layer_idx_set(const std::set& pin_layer_idx_set) { _pin_layer_idx_set = pin_layer_idx_set; } + void set_layer_cost_list(const std::vector& layer_cost_list) { _layer_cost_list = layer_cost_list; } + void set_layer_idx(const int32_t layer_idx) { _layer_idx = layer_idx; } + // function + + private: + PlanarCoord _planar_coord; + std::set _pin_layer_idx_set; + std::vector _layer_cost_list; + int32_t _layer_idx = -1; +}; +} // namespace irt diff --git a/src/operation/iRT/source/module/pin_accessor/CMakeLists.txt b/src/operation/iRT/source/module/pin_accessor/CMakeLists.txt index a2313d1ea7ff92982c064dcb0b31178096ddb516..9a8d136a5b18b5287e8b4ae285ef7cbf49e81dc1 100644 --- a/src/operation/iRT/source/module/pin_accessor/CMakeLists.txt +++ b/src/operation/iRT/source/module/pin_accessor/CMakeLists.txt @@ -2,8 +2,8 @@ if(DEBUG_IRT_PIN_ACCESSOR) message(STATUS "RT: DEBUG_IRT_PIN_ACCESSOR") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_PIN_ACCESSOR") - set(CMAKE_BUILD_TYPE "Release") + message(STATUS "RT: RELEASE_IRT_PIN_ACCESSOR") + set(CMAKE_BUILD_TYPE "Release") endif() add_library(irt_pin_accessor @@ -11,16 +11,16 @@ add_library(irt_pin_accessor ${IRT_MODULE}/pin_accessor/PinAccessor.cpp ) -target_link_libraries(irt_pin_accessor +target_link_libraries(irt_pin_accessor PUBLIC - irt_data_manager - irt_module - irt_toolkit + irt_data_manager + irt_module + irt_toolkit ) -target_include_directories(irt_pin_accessor +target_include_directories(irt_pin_accessor PUBLIC - ${IRT_MODULE}/pin_accessor/pa_data_manager - ${IRT_MODULE}/pin_accessor - + ${IRT_MODULE}/pin_accessor/pa_data_manager + ${IRT_MODULE}/pin_accessor + ) diff --git a/src/operation/iRT/source/module/pin_accessor/PinAccessor.cpp b/src/operation/iRT/source/module/pin_accessor/PinAccessor.cpp index 4f74507ac92e21d50eef1929aa84902e6d0f6fc4..4c86112b9c61cafdfb30f1632ec03413f4ec0d98 100644 --- a/src/operation/iRT/source/module/pin_accessor/PinAccessor.cpp +++ b/src/operation/iRT/source/module/pin_accessor/PinAccessor.cpp @@ -63,9 +63,9 @@ void PinAccessor::access() RTLOG.info(Loc::current(), "Starting..."); PAModel pa_model = initPAModel(); setPAComParam(pa_model); - buildBlockTrimRectMap(pa_model); initAccessPointList(pa_model); uploadAccessPointList(pa_model); + // debugPlotPAModel(pa_model, "init"); routePAModel(pa_model); uploadAccessPoint(pa_model); uploadAccessResult(pa_model); @@ -121,29 +121,6 @@ void PinAccessor::setPAComParam(PAModel& pa_model) pa_model.set_pa_com_param(pa_com_param); } -void PinAccessor::buildBlockTrimRectMap(PAModel& pa_model) -{ - std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); - std::map& layer_enclosure_map = RTDM.getDatabase().get_layer_enclosure_map(); - std::map& block_shape_map = RTDM.getDatabase().get_block_shape_map(); - - std::map>& block_layer_trim_rect_map = pa_model.get_block_layer_trim_rect_map(); - - for (auto& [block_name, shape] : block_shape_map) { - for (auto& [routing_layer_idx, enclosure] : layer_enclosure_map) { - int32_t min_width = routing_layer_list[routing_layer_idx].get_min_width(); - int32_t shrinked_x_size = std::max(min_width, enclosure.getXSpan()); - int32_t shrinked_y_size = std::max(min_width, enclosure.getYSpan()); - - PlanarRect shrink_shape = shape; - if (RTUTIL.hasShrinkedRect(shrink_shape, shrinked_x_size, shrinked_y_size)) { - shrink_shape = RTUTIL.getShrinkedRect(shrink_shape, shrinked_x_size, shrinked_y_size); - } - block_layer_trim_rect_map[block_name][routing_layer_idx] = shrink_shape; - } - } -} - void PinAccessor::initAccessPointList(PAModel& pa_model) { Monitor monitor; @@ -183,16 +160,12 @@ void PinAccessor::initAccessPointList(PAModel& pa_model) // 构建目标层 std::vector point_layer_idx_list; if (curr_layer_idx < bottom_routing_layer_idx) { - point_layer_idx_list.push_back(bottom_routing_layer_idx); point_layer_idx_list.push_back(bottom_routing_layer_idx + 1); } else if (top_routing_layer_idx < curr_layer_idx) { - point_layer_idx_list.push_back(top_routing_layer_idx); point_layer_idx_list.push_back(top_routing_layer_idx - 1); } else if (curr_layer_idx < top_routing_layer_idx) { - point_layer_idx_list.push_back(curr_layer_idx); point_layer_idx_list.push_back(curr_layer_idx + 1); } else { - point_layer_idx_list.push_back(curr_layer_idx); point_layer_idx_list.push_back(curr_layer_idx - 1); } // 构建搜索形状 @@ -249,8 +222,6 @@ std::vector PinAccessor::getPlanarLegalRectList(PAModel& pa_model, i std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::map& layer_enclosure_map = RTDM.getDatabase().get_layer_enclosure_map(); - std::map>& block_layer_trim_rect_map = pa_model.get_block_layer_trim_rect_map(); - int32_t curr_layer_idx; { for (EXTLayerRect& pin_shape : pin_shape_list) { @@ -265,15 +236,6 @@ std::vector PinAccessor::getPlanarLegalRectList(PAModel& pa_model, i for (EXTLayerRect& pin_shape : pin_shape_list) { origin_pin_shape_list.push_back(pin_shape.get_real_rect()); } - // 对macro的pin先剪裁 - std::string instance_name = RTUTIL.splitString(pa_pin->get_pin_name(), ':').front(); - if (RTUTIL.exist(block_layer_trim_rect_map, instance_name)) { - std::vector trim_pin_shape_list - = RTUTIL.getOpenCuttingRectListByBoost(origin_pin_shape_list, {block_layer_trim_rect_map[instance_name][curr_layer_idx]}); - if (!trim_pin_shape_list.empty()) { - origin_pin_shape_list = trim_pin_shape_list; - } - } } // 当前层缩小后的结果 std::vector shrinked_rect_list; @@ -561,16 +523,12 @@ void PinAccessor::routePAModel(PAModel& pa_model) */ std::vector pa_iter_param_list; // clang-format off - pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 0, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); - pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 1, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); - pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 2, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); - pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 3, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); - pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 4, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); - pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 0, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); - pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 1, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); - pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 2, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); - pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 3, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); - pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 5, 4, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); + pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 3, 0, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); + pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 3, 1, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); + pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 3, 2, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); + pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 3, 0, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); + pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 3, 1, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); + pa_iter_param_list.emplace_back(prefer_wire_unit, non_prefer_wire_unit, via_unit, 3, 2, 3, fixed_rect_unit, routed_rect_unit, violation_unit, 20, 10); // clang-format on initRoutingState(pa_model); for (int32_t i = 0, iter = 1; i < static_cast(pa_iter_param_list.size()); i++, iter++) { @@ -591,8 +549,7 @@ void PinAccessor::routePAModel(PAModel& pa_model) printSummary(pa_model); outputNetCSV(pa_model); outputViolationCSV(pa_model); - outputNetJson(pa_model); - outputViolationJson(pa_model); + outputJson(pa_model); RTLOG.info(Loc::current(), "***** End Iteration ", iter, "/", pa_iter_param_list.size(), "(", RTUTIL.getPercentage(iter, pa_iter_param_list.size()), ")", iter_monitor.getStatsInfo(), "*****"); if (stopIteration(pa_model)) { @@ -627,31 +584,53 @@ void PinAccessor::setPAIterParam(PAModel& pa_model, int32_t iter, PAIterParam& p void PinAccessor::initPABoxMap(PAModel& pa_model) { ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); - - int32_t x_gcell_num = 0; - for (ScaleGrid& x_grid : gcell_axis.get_x_grid_list()) { - x_gcell_num += x_grid.get_step_num(); - } - int32_t y_gcell_num = 0; - for (ScaleGrid& y_grid : gcell_axis.get_y_grid_list()) { - y_gcell_num += y_grid.get_step_num(); - } - PAIterParam& pa_iter_param = pa_model.get_pa_iter_param(); + int32_t size = pa_iter_param.get_size(); int32_t offset = pa_iter_param.get_offset(); - int32_t x_box_num = static_cast(std::ceil((x_gcell_num - offset) / 1.0 / size)); - int32_t y_box_num = static_cast(std::ceil((y_gcell_num - offset) / 1.0 / size)); - + while (offset >= size) { + offset -= size; + } + std::vector x_scale_list; + { + int32_t x_gcell_num = 0; + for (ScaleGrid& x_grid : gcell_axis.get_x_grid_list()) { + x_gcell_num += x_grid.get_step_num(); + } + x_scale_list.push_back(0); + for (int32_t x_scale = offset; x_scale <= x_gcell_num; x_scale += size) { + x_scale_list.push_back(x_scale); + } + x_scale_list.push_back(x_gcell_num); + std::sort(x_scale_list.begin(), x_scale_list.end()); + x_scale_list.erase(std::unique(x_scale_list.begin(), x_scale_list.end()), x_scale_list.end()); + } + std::vector y_scale_list; + { + int32_t y_gcell_num = 0; + for (ScaleGrid& y_grid : gcell_axis.get_y_grid_list()) { + y_gcell_num += y_grid.get_step_num(); + } + y_scale_list.push_back(0); + for (int32_t y_scale = offset; y_scale <= y_gcell_num; y_scale += size) { + y_scale_list.push_back(y_scale); + } + y_scale_list.push_back(y_gcell_num); + std::sort(y_scale_list.begin(), y_scale_list.end()); + y_scale_list.erase(std::unique(y_scale_list.begin(), y_scale_list.end()), y_scale_list.end()); + } GridMap& pa_box_map = pa_model.get_pa_box_map(); - pa_box_map.init(x_box_num, y_box_num); - + { + int32_t x_box_num = static_cast(x_scale_list.size()) - 1; + int32_t y_box_num = static_cast(y_scale_list.size()) - 1; + pa_box_map.init(x_box_num, y_box_num); + } for (int32_t x = 0; x < pa_box_map.get_x_size(); x++) { for (int32_t y = 0; y < pa_box_map.get_y_size(); y++) { - int32_t grid_ll_x = std::max(offset + x * size, 0); - int32_t grid_ll_y = std::max(offset + y * size, 0); - int32_t grid_ur_x = std::min(offset + (x + 1) * size - 1, x_gcell_num - 1); - int32_t grid_ur_y = std::min(offset + (y + 1) * size - 1, y_gcell_num - 1); + int32_t grid_ll_x = x_scale_list[x]; + int32_t grid_ll_y = y_scale_list[y]; + int32_t grid_ur_x = x_scale_list[x + 1] - 1; + int32_t grid_ur_y = y_scale_list[y + 1] - 1; PlanarRect ll_gcell_rect = RTUTIL.getRealRectByGCell(PlanarCoord(grid_ll_x, grid_ll_y), gcell_axis); PlanarRect ur_gcell_rect = RTUTIL.getRealRectByGCell(PlanarCoord(grid_ur_x, grid_ur_y), gcell_axis); @@ -692,7 +671,9 @@ void PinAccessor::buildBoxSchedule(PAModel& pa_model) pa_box_id_list.emplace_back(x, y); } } - pa_box_id_list_list.push_back(pa_box_id_list); + if (!pa_box_id_list.empty()) { + pa_box_id_list_list.push_back(pa_box_id_list); + } } } pa_model.set_pa_box_id_list_list(pa_box_id_list_list); @@ -851,6 +832,14 @@ void PinAccessor::initPATaskList(PAModel& pa_model, PABox& pa_box) pa_group_list.back().get_coord_list().push_back(coord); } } + if (pa_group_list.back().get_coord_list().empty()) { + for (const LayerCoord& coord : pa_pin->get_target_coord_list()) { + if (!RTUTIL.isInside(box_rect.get_real_rect(), coord.get_planar_coord())) { + continue; + } + pa_group_list.back().get_coord_list().push_back(coord); + } + } } if (pa_group_list.front().get_coord_list().empty() || pa_group_list.back().get_coord_list().empty()) { continue; @@ -966,17 +955,58 @@ bool PinAccessor::needRouting(PABox& pa_box) void PinAccessor::buildBoxTrackAxis(PABox& pa_box) { + int32_t manufacture_grid = RTDM.getDatabase().get_manufacture_grid(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector x_scale_list; std::vector y_scale_list; PlanarRect& box_real_rect = pa_box.get_box_rect().get_real_rect(); + int32_t ll_x = box_real_rect.get_ll_x(); + int32_t ll_y = box_real_rect.get_ll_y(); + int32_t ur_x = box_real_rect.get_ur_x(); + int32_t ur_y = box_real_rect.get_ur_y(); + // 避免 off_grid + while (ll_x % manufacture_grid != 0) { + ll_x++; + } + while (ll_y % manufacture_grid != 0) { + ll_y++; + } + while (ur_x % manufacture_grid != 0) { + ur_x--; + } + while (ur_y % manufacture_grid != 0) { + ur_y--; + } + std::map, std::set>>& layer_axis_map = pa_box.get_layer_axis_map(); + for (RoutingLayer& routing_layer : routing_layer_list) { + for (int32_t x_scale : RTUTIL.getScaleList(ll_x, ur_x, routing_layer.getXTrackGridList())) { + if (routing_layer.isPreferH()) + layer_axis_map[routing_layer.get_layer_idx()].first.insert(x_scale); + } + for (int32_t y_scale : RTUTIL.getScaleList(ll_y, ur_y, routing_layer.getYTrackGridList())) { + if (!routing_layer.isPreferH()) + layer_axis_map[routing_layer.get_layer_idx()].second.insert(y_scale); + } + } + for (PATask* pa_task : pa_box.get_pa_task_list()) { + for (PAGroup& pa_group : pa_task->get_pa_group_list()) { + for (LayerCoord& coord : pa_group.get_coord_list()) { + int32_t layer_idx = coord.get_layer_idx(); + if (routing_layer_list[layer_idx].isPreferH()) { + layer_axis_map[layer_idx].first.insert(coord.get_x()); + } else { + layer_axis_map[layer_idx].second.insert(coord.get_y()); + } + } + } + } for (RoutingLayer& routing_layer : routing_layer_list) { - for (int32_t x_scale : RTUTIL.getScaleList(box_real_rect.get_ll_x(), box_real_rect.get_ur_x(), routing_layer.getXTrackGridList())) { + for (int32_t x_scale : RTUTIL.getScaleList(ll_x, ur_x, routing_layer.getXTrackGridList())) { x_scale_list.push_back(x_scale); } - for (int32_t y_scale : RTUTIL.getScaleList(box_real_rect.get_ll_y(), box_real_rect.get_ur_y(), routing_layer.getYTrackGridList())) { + for (int32_t y_scale : RTUTIL.getScaleList(ll_y, ur_y, routing_layer.getYTrackGridList())) { y_scale_list.push_back(y_scale); } } @@ -1037,6 +1067,7 @@ void PinAccessor::buildPANodeNeighbor(PABox& pa_box) int32_t top_routing_layer_idx = RTDM.getConfig().top_routing_layer_idx; std::vector>& layer_node_map = pa_box.get_layer_node_map(); + std::map, std::set>>& layer_axis_map = pa_box.get_layer_axis_map(); for (int32_t layer_idx = 0; layer_idx < static_cast(layer_node_map.size()); layer_idx++) { bool routing_hv = true; if (layer_idx < bottom_routing_layer_idx || top_routing_layer_idx < layer_idx) { @@ -1046,18 +1077,66 @@ void PinAccessor::buildPANodeNeighbor(PABox& pa_box) for (int32_t x = 0; x < pa_node_map.get_x_size(); x++) { for (int32_t y = 0; y < pa_node_map.get_y_size(); y++) { std::map& neighbor_node_map = pa_node_map[x][y].get_neighbor_node_map(); - if (routing_hv) { - if (x != 0) { - neighbor_node_map[Orientation::kWest] = &pa_node_map[x - 1][y]; + std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); + std::set neighbor_layer_x_axis_set; + std::set neighbor_layer_y_axis_set; + if (layer_idx != 0) { + for (int32_t x_scale : layer_axis_map[layer_idx - 1].first) { + neighbor_layer_x_axis_set.insert(x_scale); } - if (x != (pa_node_map.get_x_size() - 1)) { - neighbor_node_map[Orientation::kEast] = &pa_node_map[x + 1][y]; + for (int32_t y_scale : layer_axis_map[layer_idx - 1].second) { + neighbor_layer_y_axis_set.insert(y_scale); } - if (y != 0) { - neighbor_node_map[Orientation::kSouth] = &pa_node_map[x][y - 1]; + } + if (layer_idx != static_cast(layer_node_map.size()) - 1) { + for (int32_t x_scale : layer_axis_map[layer_idx + 1].first) { + neighbor_layer_x_axis_set.insert(x_scale); + } + for (int32_t y_scale : layer_axis_map[layer_idx + 1].second) { + neighbor_layer_y_axis_set.insert(y_scale); } - if (y != (pa_node_map.get_y_size() - 1)) { - neighbor_node_map[Orientation::kNorth] = &pa_node_map[x][y + 1]; + } + std::set curr_axis; + if (routing_layer_list[layer_idx].isPreferH()) { + curr_axis = layer_axis_map[layer_idx].first; + } else { + curr_axis = layer_axis_map[layer_idx].second; + } + if (routing_hv) { + if (!routing_layer_list[layer_idx].isPreferH()) { + if (RTUTIL.exist(curr_axis, pa_node_map[x][y].get_y())) { + if (x != 0) { + neighbor_node_map[Orientation::kWest] = &pa_node_map[x - 1][y]; + } + if (x != (pa_node_map.get_x_size() - 1)) { + neighbor_node_map[Orientation::kEast] = &pa_node_map[x + 1][y]; + } + } + if (RTUTIL.exist(neighbor_layer_x_axis_set, pa_node_map[x][y].get_x())) { + if (y != 0) { + neighbor_node_map[Orientation::kSouth] = &pa_node_map[x][y - 1]; + } + if (y != (pa_node_map.get_y_size() - 1)) { + neighbor_node_map[Orientation::kNorth] = &pa_node_map[x][y + 1]; + } + } + } else if (routing_layer_list[layer_idx].isPreferH()) { + if (RTUTIL.exist(curr_axis, pa_node_map[x][y].get_x())) { + if (y != 0) { + neighbor_node_map[Orientation::kSouth] = &pa_node_map[x][y - 1]; + } + if (y != (pa_node_map.get_y_size() - 1)) { + neighbor_node_map[Orientation::kNorth] = &pa_node_map[x][y + 1]; + } + } + if (RTUTIL.exist(neighbor_layer_y_axis_set, pa_node_map[x][y].get_y())) { + if (x != 0) { + neighbor_node_map[Orientation::kWest] = &pa_node_map[x - 1][y]; + } + if (x != (pa_node_map.get_x_size() - 1)) { + neighbor_node_map[Orientation::kEast] = &pa_node_map[x + 1][y]; + } + } } } if (layer_idx != 0) { @@ -1699,11 +1778,12 @@ void PinAccessor::initSinglePatchTask(PABox& pa_box, PATask* pa_task) // single task pa_box.set_curr_patch_task(pa_task); pa_box.get_routing_patch_list().clear(); - pa_box.set_patch_violation_list(getPatchViolationList(pa_box)); + pa_box.set_patch_violation_list(getPatchViolationList(pa_box, {ViolationType::kMinimumArea}, {})); pa_box.get_tried_fix_violation_set().clear(); } -std::vector PinAccessor::getPatchViolationList(PABox& pa_box) +std::vector PinAccessor::getPatchViolationList(PABox& pa_box, const std::set& check_type_set, + const std::vector& check_region_list) { std::string top_name = RTUTIL.getString("pa_box_", pa_box.get_pa_box_id().get_x(), "_", pa_box.get_pa_box_id().get_y()); std::vector> env_shape_list; @@ -1773,6 +1853,8 @@ std::vector PinAccessor::getPatchViolationList(PABox& pa_box) de_task.set_net_result_map(net_result_map); de_task.set_net_patch_map(net_patch_map); de_task.set_need_checked_net_set(need_checked_net_set); + de_task.set_check_type_set(check_type_set); + de_task.set_check_region_list(check_region_list); return RTDE.getViolationList(de_task); } @@ -1829,7 +1911,7 @@ std::vector PinAccessor::getViolationOverlapRect(PABox& pa_box, Viol } } for (Segment* segment : pa_box.get_net_pin_access_result_map()[curr_net_idx][curr_pin_idx]) { - for (NetShape& net_shape : RTDM.getNetShapeList(curr_net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(curr_net_idx, *segment)) { if (!net_shape.get_is_routing()) { continue; } @@ -1839,7 +1921,7 @@ std::vector PinAccessor::getViolationOverlapRect(PABox& pa_box, Viol } } for (Segment& segment : pa_box.get_net_task_access_result_map()[curr_net_idx][curr_task_idx]) { - for (NetShape& net_shape : RTDM.getNetShapeList(curr_net_idx, segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(curr_net_idx, segment)) { if (!net_shape.get_is_routing()) { continue; } @@ -1890,19 +1972,35 @@ void PinAccessor::addViolationToShadow(PABox& pa_box) void PinAccessor::patchSingleViolation(PABox& pa_box) { + std::vector& routing_patch_list = pa_box.get_routing_patch_list(); + std::set& tried_fix_violation_set = pa_box.get_tried_fix_violation_set(); + LayerRect violation_rect = pa_box.get_curr_patch_violation().get_violation_shape().getRealLayerRect(); + std::vector pa_patch_list = getCandidatePatchList(pa_box); - for (PAPatch& pa_patch : pa_patch_list) { - buildSingleViolation(pa_box, pa_patch); - if (pa_box.get_curr_is_solved()) { - updateSingleViolation(pa_box); - break; + if (pa_patch_list.size() == 1) { + routing_patch_list.push_back(pa_patch_list.front().get_patch()); + } else if (pa_patch_list.size() >= 2) { + std::vector origin_patch_violation_list = getPatchViolationList(pa_box, {}, {violation_rect}); + + bool curr_is_solved = false; + for (PAPatch& pa_patch : pa_patch_list) { + std::vector curr_patch_violation_list; + { + routing_patch_list.push_back(pa_patch.get_patch()); + curr_patch_violation_list = getPatchViolationList(pa_box, {}, {violation_rect}); + routing_patch_list.pop_back(); + } + curr_is_solved = getSolvedStatus(pa_box, origin_patch_violation_list, curr_patch_violation_list); + if (curr_is_solved) { + routing_patch_list.push_back(pa_patch.get_patch()); + break; + } + } + if (!curr_is_solved) { + routing_patch_list.push_back(pa_patch_list.front().get_patch()); } } - if (!pa_patch_list.empty() && !pa_box.get_curr_is_solved()) { - buildSingleViolation(pa_box, pa_patch_list.front()); - updateSingleViolation(pa_box); - } - updateTriedFixViolation(pa_box); + tried_fix_violation_set.insert(pa_box.get_curr_patch_violation()); } std::vector PinAccessor::getCandidatePatchList(PABox& pa_box) @@ -2034,67 +2132,56 @@ std::vector PinAccessor::getCandidatePatchList(PABox& pa_box) return candidate_patch_list; } -void PinAccessor::buildSingleViolation(PABox& pa_box, PAPatch& pa_patch) +bool PinAccessor::getSolvedStatus(PABox& pa_box, std::vector& origin_patch_violation_list, std::vector& curr_patch_violation_list) { - { - pa_box.set_curr_candidate_patch(pa_patch); - } - { - pa_box.get_routing_patch_list().push_back(pa_patch.get_patch()); - pa_box.set_curr_patch_violation_list(getPatchViolationList(pa_box)); - pa_box.get_routing_patch_list().pop_back(); + std::map> env_type_origin_curr_map; + std::map> valid_type_origin_curr_map; + std::map> within_net_map; + for (Violation& origin_violation : origin_patch_violation_list) { + if (!isValidPatchViolation(pa_box, origin_violation)) { + env_type_origin_curr_map[origin_violation.get_violation_type()].first++; + } else { + valid_type_origin_curr_map[origin_violation.get_violation_type()].first++; + } + if (origin_violation.get_violation_net_set().size() > 1) { + within_net_map[origin_violation.get_violation_type()].first++; + } } - { - std::map> env_type_origin_curr_map; - std::map> valid_type_origin_curr_map; - for (Violation& origin_violation : pa_box.get_patch_violation_list()) { - if (!isValidPatchViolation(pa_box, origin_violation)) { - env_type_origin_curr_map[origin_violation.get_violation_type()].first++; - } else { - valid_type_origin_curr_map[origin_violation.get_violation_type()].first++; - } + for (Violation& curr_violation : curr_patch_violation_list) { + if (!isValidPatchViolation(pa_box, curr_violation)) { + env_type_origin_curr_map[curr_violation.get_violation_type()].second++; + } else { + valid_type_origin_curr_map[curr_violation.get_violation_type()].second++; } - for (Violation& curr_violation : pa_box.get_curr_patch_violation_list()) { - if (!isValidPatchViolation(pa_box, curr_violation)) { - env_type_origin_curr_map[curr_violation.get_violation_type()].second++; - } else { - valid_type_origin_curr_map[curr_violation.get_violation_type()].second++; - } + if (curr_violation.get_violation_net_set().size() > 1) { + within_net_map[curr_violation.get_violation_type()].second++; } - bool is_solved = true; - for (auto& [violation_type, origin_curr] : env_type_origin_curr_map) { - if (!is_solved) { - break; - } - is_solved = origin_curr.second <= origin_curr.first; + } + bool curr_is_solved = true; + for (auto& [violation_type, origin_curr] : env_type_origin_curr_map) { + if (!curr_is_solved) { + break; } - for (auto& [violation_type, origin_curr] : valid_type_origin_curr_map) { - if (!is_solved) { - break; - } - is_solved = origin_curr.second < origin_curr.first; + curr_is_solved = origin_curr.second <= origin_curr.first; + } + for (auto& [violation_type, origin_curr] : valid_type_origin_curr_map) { + if (!curr_is_solved) { + break; } - pa_box.set_curr_is_solved(is_solved); + curr_is_solved = origin_curr.second < origin_curr.first; } -} - -void PinAccessor::updateSingleViolation(PABox& pa_box) -{ - pa_box.get_routing_patch_list().push_back(pa_box.get_curr_candidate_patch().get_patch()); - pa_box.set_patch_violation_list(pa_box.get_curr_patch_violation_list()); -} - -void PinAccessor::updateTriedFixViolation(PABox& pa_box) -{ - pa_box.get_tried_fix_violation_set().insert(pa_box.get_curr_patch_violation()); + for (auto& [violation_type, origin_curr] : within_net_map) { + if (!curr_is_solved) { + break; + } + curr_is_solved = origin_curr.second <= origin_curr.first; + } + return curr_is_solved; } void PinAccessor::resetSingleViolation(PABox& pa_box) { pa_box.set_curr_patch_violation(Violation()); - pa_box.set_curr_candidate_patch(PAPatch()); - pa_box.get_curr_patch_violation_list().clear(); - pa_box.set_curr_is_solved(false); } void PinAccessor::clearViolationShadow(PABox& pa_box) @@ -2473,8 +2560,7 @@ void PinAccessor::selectBestResult(PAModel& pa_model) printSummary(pa_model); outputNetCSV(pa_model); outputViolationCSV(pa_model); - outputNetJson(pa_model); - outputViolationJson(pa_model); + outputJson(pa_model); RTLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); } @@ -2625,7 +2711,7 @@ void PinAccessor::updateFixedRectToGraph(PABox& pa_box, ChangeType change_type, void PinAccessor::updateFixedRectToGraph(PABox& pa_box, ChangeType change_type, int32_t net_idx, Segment* segment) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { for (auto& [pa_node, orientation_set] : getNodeOrientationMap(pa_box, net_shape)) { for (Orientation orientation : orientation_set) { if (change_type == ChangeType::kAdd) { @@ -2654,7 +2740,7 @@ void PinAccessor::updateRoutedRectToGraph(PABox& pa_box, ChangeType change_type, void PinAccessor::updateRoutedRectToGraph(PABox& pa_box, ChangeType change_type, int32_t net_idx, Segment& segment) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, segment)) { for (auto& [pa_node, orientation_set] : getNodeOrientationMap(pa_box, net_shape)) { for (Orientation orientation : orientation_set) { if (change_type == ChangeType::kAdd) { @@ -3003,7 +3089,7 @@ void PinAccessor::updateFixedRectToShadow(PABox& pa_box, ChangeType change_type, void PinAccessor::updateFixedRectToShadow(PABox& pa_box, ChangeType change_type, int32_t net_idx, Segment* segment) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { if (!net_shape.get_is_routing()) { continue; } @@ -3036,7 +3122,7 @@ void PinAccessor::updateRoutedRectToShadow(PABox& pa_box, ChangeType change_type void PinAccessor::updateRoutedRectToShadow(PABox& pa_box, ChangeType change_type, int32_t net_idx, Segment& segment) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, segment)) { if (!net_shape.get_is_routing()) { continue; } @@ -3199,8 +3285,6 @@ void PinAccessor::updateSummary(PAModel& pa_model) std::vector>& layer_via_master_list = RTDM.getDatabase().get_layer_via_master_list(); Summary& summary = RTDM.getDatabase().get_summary(); - std::map& routing_access_point_num_map = summary.iter_pa_summary_map[pa_model.get_iter()].routing_access_point_num_map; - int32_t& total_access_point_num = summary.iter_pa_summary_map[pa_model.get_iter()].total_access_point_num; std::map& routing_wire_length_map = summary.iter_pa_summary_map[pa_model.get_iter()].routing_wire_length_map; double& total_wire_length = summary.iter_pa_summary_map[pa_model.get_iter()].total_wire_length; std::map& cut_via_num_map = summary.iter_pa_summary_map[pa_model.get_iter()].cut_via_num_map; @@ -3210,10 +3294,6 @@ void PinAccessor::updateSummary(PAModel& pa_model) std::map& routing_violation_num_map = summary.iter_pa_summary_map[pa_model.get_iter()].routing_violation_num_map; int32_t& total_violation_num = summary.iter_pa_summary_map[pa_model.get_iter()].total_violation_num; - std::vector& pa_net_list = pa_model.get_pa_net_list(); - - routing_access_point_num_map.clear(); - total_access_point_num = 0; routing_wire_length_map.clear(); total_wire_length = 0; cut_via_num_map.clear(); @@ -3223,12 +3303,6 @@ void PinAccessor::updateSummary(PAModel& pa_model) routing_violation_num_map.clear(); total_violation_num = 0; - for (PANet& pa_net : pa_net_list) { - for (PAPin& pa_pin : pa_net.get_pa_pin_list()) { - routing_access_point_num_map[pa_pin.get_access_point().get_layer_idx()]++; - total_access_point_num++; - } - } for (auto& [net_idx, pin_access_result_map] : RTDM.getNetPinAccessResultMap(die)) { for (auto& [pin_idx, segment_set] : pin_access_result_map) { for (Segment* segment : segment_set) { @@ -3271,8 +3345,6 @@ void PinAccessor::printSummary(PAModel& pa_model) std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); Summary& summary = RTDM.getDatabase().get_summary(); - std::map& routing_access_point_num_map = summary.iter_pa_summary_map[pa_model.get_iter()].routing_access_point_num_map; - int32_t& total_access_point_num = summary.iter_pa_summary_map[pa_model.get_iter()].total_access_point_num; std::map& routing_wire_length_map = summary.iter_pa_summary_map[pa_model.get_iter()].routing_wire_length_map; double& total_wire_length = summary.iter_pa_summary_map[pa_model.get_iter()].total_wire_length; std::map& cut_via_num_map = summary.iter_pa_summary_map[pa_model.get_iter()].cut_via_num_map; @@ -3282,20 +3354,6 @@ void PinAccessor::printSummary(PAModel& pa_model) std::map& routing_violation_num_map = summary.iter_pa_summary_map[pa_model.get_iter()].routing_violation_num_map; int32_t& total_violation_num = summary.iter_pa_summary_map[pa_model.get_iter()].total_violation_num; - fort::char_table routing_access_point_num_map_table; - { - routing_access_point_num_map_table.set_cell_text_align(fort::text_align::right); - routing_access_point_num_map_table << fort::header << "routing" - << "#access_point" - << "prop" << fort::endr; - for (RoutingLayer& routing_layer : routing_layer_list) { - routing_access_point_num_map_table << routing_layer.get_layer_name() << routing_access_point_num_map[routing_layer.get_layer_idx()] - << RTUTIL.getPercentage(routing_access_point_num_map[routing_layer.get_layer_idx()], total_access_point_num) - << fort::endr; - } - routing_access_point_num_map_table << fort::header << "Total" << total_access_point_num - << RTUTIL.getPercentage(total_access_point_num, total_access_point_num) << fort::endr; - } fort::char_table routing_wire_length_map_table; { routing_wire_length_map_table.set_cell_text_align(fort::text_align::right); @@ -3441,62 +3499,72 @@ void PinAccessor::outputViolationCSV(PAModel& pa_model) } } -void PinAccessor::outputNetJson(PAModel& pa_model) +void PinAccessor::outputJson(PAModel& pa_model) +{ + int32_t enable_notification = RTDM.getConfig().enable_notification; + if (!enable_notification) { + return; + } + std::map json_path_map; + json_path_map["net_map"] = outputNetJson(pa_model); + json_path_map["violation_map"] = outputViolationJson(pa_model); + json_path_map["summary"] = outputSummaryJson(pa_model); + RTI.sendNotification("PA", pa_model.get_iter(), json_path_map); +} + +std::string PinAccessor::outputNetJson(PAModel& pa_model) { Die& die = RTDM.getDatabase().get_die(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); std::vector& net_list = RTDM.getDatabase().get_net_list(); std::string& pa_temp_directory_path = RTDM.getConfig().pa_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector net_json_list; - net_json_list.resize(net_list.size()); - for (Net& net : net_list) { - net_json_list[net.get_net_idx()]["net_name"] = net.get_net_name(); - } - for (auto& [net_idx, pin_access_result_map] : RTDM.getNetPinAccessResultMap(die)) { - for (auto& [pin_idx, segment_set] : pin_access_result_map) { - for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { - std::string layer_name; - if (net_shape.get_is_routing()) { - layer_name = routing_layer_list[net_shape.get_layer_idx()].get_layer_name(); - } else { - layer_name = cut_layer_list[net_shape.get_layer_idx()].get_layer_name(); + { + nlohmann::json result_shape_json; + for (auto& [net_idx, pin_access_result_map] : RTDM.getNetPinAccessResultMap(die)) { + std::string net_name = net_list[net_idx].get_net_name(); + for (auto& [pin_idx, segment_set] : pin_access_result_map) { + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { + std::string layer_name; + if (net_shape.get_is_routing()) { + layer_name = routing_layer_list[net_shape.get_layer_idx()].get_layer_name(); + } else { + layer_name = cut_layer_list[net_shape.get_layer_idx()].get_layer_name(); + } + result_shape_json["result_shape"][net_name]["path"].push_back( + {net_shape.get_ll_x(), net_shape.get_ll_y(), net_shape.get_ur_x(), net_shape.get_ur_y(), layer_name}); } - net_json_list[net_idx]["result"].push_back({net_shape.get_ll_x(), net_shape.get_ll_y(), net_shape.get_ur_x(), net_shape.get_ur_y(), layer_name}); } } } - } - for (auto& [net_idx, pin_access_patch_map] : RTDM.getNetPinAccessPatchMap(die)) { - for (auto& [pin_idx, patch_set] : pin_access_patch_map) { - for (EXTLayerRect* patch : patch_set) { - net_json_list[net_idx]["patch"].push_back({patch->get_real_ll_x(), patch->get_real_ll_y(), patch->get_real_ur_x(), patch->get_real_ur_y(), - routing_layer_list[patch->get_layer_idx()].get_layer_name()}); + for (auto& [net_idx, pin_access_patch_map] : RTDM.getNetPinAccessPatchMap(die)) { + std::string net_name = net_list[net_idx].get_net_name(); + for (auto& [pin_idx, patch_set] : pin_access_patch_map) { + for (EXTLayerRect* patch : patch_set) { + result_shape_json["result_shape"][net_name]["patch"].push_back({patch->get_real_ll_x(), patch->get_real_ll_y(), patch->get_real_ur_x(), + patch->get_real_ur_y(), routing_layer_list[patch->get_layer_idx()].get_layer_name()}); + } } } + net_json_list.push_back(result_shape_json); } std::string net_json_file_path = RTUTIL.getString(pa_temp_directory_path, "net_map_", pa_model.get_iter(), ".json"); std::ofstream* net_json_file = RTUTIL.getOutputFileStream(net_json_file_path); (*net_json_file) << net_json_list; RTUTIL.closeFileStream(net_json_file); - RTI.sendNotification(RTUTIL.getString("PA_", pa_model.get_iter(), "_net_map"), net_json_file_path); + return net_json_file_path; } -void PinAccessor::outputViolationJson(PAModel& pa_model) +std::string PinAccessor::outputViolationJson(PAModel& pa_model) { Die& die = RTDM.getDatabase().get_die(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& net_list = RTDM.getDatabase().get_net_list(); std::string& pa_temp_directory_path = RTDM.getConfig().pa_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector violation_json_list; for (Violation* violation : RTDM.getViolationSet(die)) { EXTLayerRect& violation_shape = violation->get_violation_shape(); @@ -3507,7 +3575,11 @@ void PinAccessor::outputViolationJson(PAModel& pa_model) = {violation_shape.get_real_rect().get_ll_x(), violation_shape.get_real_rect().get_ll_y(), violation_shape.get_real_rect().get_ur_x(), violation_shape.get_real_rect().get_ur_y(), routing_layer_list[violation_shape.get_layer_idx()].get_layer_name()}; for (int32_t net_idx : violation->get_violation_net_set()) { - violation_json["net"].push_back(net_list[net_idx].get_net_name()); + if (net_idx != -1) { + violation_json["net"].push_back(net_list[net_idx].get_net_name()); + } else { + violation_json["net"].push_back("obs"); + } } violation_json_list.push_back(violation_json); } @@ -3515,7 +3587,49 @@ void PinAccessor::outputViolationJson(PAModel& pa_model) std::ofstream* violation_json_file = RTUTIL.getOutputFileStream(violation_json_file_path); (*violation_json_file) << violation_json_list; RTUTIL.closeFileStream(violation_json_file); - RTI.sendNotification(RTUTIL.getString("PA_", pa_model.get_iter(), "_violation_map"), violation_json_file_path); + return violation_json_file_path; +} + +std::string PinAccessor::outputSummaryJson(PAModel& pa_model) +{ + std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); + std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); + Summary& summary = RTDM.getDatabase().get_summary(); + std::string& pa_temp_directory_path = RTDM.getConfig().pa_temp_directory_path; + + std::map& routing_wire_length_map = summary.iter_pa_summary_map[pa_model.get_iter()].routing_wire_length_map; + double& total_wire_length = summary.iter_pa_summary_map[pa_model.get_iter()].total_wire_length; + std::map& cut_via_num_map = summary.iter_pa_summary_map[pa_model.get_iter()].cut_via_num_map; + int32_t& total_via_num = summary.iter_pa_summary_map[pa_model.get_iter()].total_via_num; + std::map& routing_patch_num_map = summary.iter_pa_summary_map[pa_model.get_iter()].routing_patch_num_map; + int32_t& total_patch_num = summary.iter_pa_summary_map[pa_model.get_iter()].total_patch_num; + std::map& routing_violation_num_map = summary.iter_pa_summary_map[pa_model.get_iter()].routing_violation_num_map; + int32_t& total_violation_num = summary.iter_pa_summary_map[pa_model.get_iter()].total_violation_num; + + nlohmann::json summary_json; + summary_json["iter"] = pa_model.get_iter(); + for (auto& [routing_layer_idx, wire_length] : routing_wire_length_map) { + summary_json["routing_wire_length_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = wire_length; + } + summary_json["total_wire_length"] = total_wire_length; + for (auto& [cut_layer_idx, via_num] : cut_via_num_map) { + summary_json["cut_via_num_map"][cut_layer_list[cut_layer_idx].get_layer_name()] = via_num; + } + summary_json["total_via_num"] = total_via_num; + for (auto& [routing_layer_idx, patch_num] : routing_patch_num_map) { + summary_json["routing_patch_num_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = patch_num; + } + summary_json["total_patch_num"] = total_patch_num; + for (auto& [routing_layer_idx, violation_num] : routing_violation_num_map) { + summary_json["routing_violation_num_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = violation_num; + } + summary_json["total_violation_num"] = total_violation_num; + + std::string summary_json_file_path = RTUTIL.getString(pa_temp_directory_path, "summary_", pa_model.get_iter(), ".json"); + std::ofstream* summary_json_file = RTUTIL.getOutputFileStream(summary_json_file_path); + (*summary_json_file) << summary_json; + RTUTIL.closeFileStream(summary_json_file); + return summary_json_file_path; } #endif @@ -3533,6 +3647,17 @@ void PinAccessor::debugPlotPAModel(PAModel& pa_model, std::string flag) GPGDS gp_gds; + // base_region + { + GPStruct base_region_struct("base_region"); + GPBoundary gp_boundary; + gp_boundary.set_layer_idx(0); + gp_boundary.set_data_type(0); + gp_boundary.set_rect(die.get_real_rect()); + base_region_struct.push(gp_boundary); + gp_gds.addStruct(base_region_struct); + } + // gcell_axis { GPStruct gcell_axis_struct("gcell_axis"); @@ -3621,9 +3746,9 @@ void PinAccessor::debugPlotPAModel(PAModel& pa_model, std::string flag) GPStruct access_result_struct(RTUTIL.getString("access_result(net_", net_idx, ")")); for (auto& [pin_idx, segment_set] : pin_access_result_map) { for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { GPBoundary gp_boundary; - gp_boundary.set_data_type(static_cast(GPDataType::kPath)); + gp_boundary.set_data_type(static_cast(GPDataType::kDetailedPath)); gp_boundary.set_rect(net_shape.get_rect()); if (net_shape.get_is_routing()) { gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); @@ -3852,7 +3977,7 @@ void PinAccessor::debugPlotPABox(PABox& pa_box, std::string flag) GPStruct access_result_struct(RTUTIL.getString("access_result(net_", net_idx, ")")); for (auto& [pin_idx, segment_set] : pin_access_result_map) { for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { GPBoundary gp_boundary; gp_boundary.set_data_type(static_cast(GPDataType::kShape)); gp_boundary.set_rect(net_shape.get_rect()); @@ -4138,9 +4263,9 @@ void PinAccessor::debugPlotPABox(PABox& pa_box, std::string flag) task_struct.push(gp_boundary); } for (Segment& segment : pa_box.get_net_task_access_result_map()[pa_task->get_net_idx()][pa_task->get_task_idx()]) { - for (NetShape& net_shape : RTDM.getNetShapeList(pa_task->get_net_idx(), segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(pa_task->get_net_idx(), segment)) { GPBoundary gp_boundary; - gp_boundary.set_data_type(static_cast(GPDataType::kPath)); + gp_boundary.set_data_type(static_cast(GPDataType::kDetailedPath)); gp_boundary.set_rect(net_shape.get_rect()); if (net_shape.get_is_routing()) { gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); diff --git a/src/operation/iRT/source/module/pin_accessor/PinAccessor.hpp b/src/operation/iRT/source/module/pin_accessor/PinAccessor.hpp index be473b7ce228c7129cc033e90ba2d7f55bf67800..70835aaeebdb83b9d08167673cb1ab24e4952401 100644 --- a/src/operation/iRT/source/module/pin_accessor/PinAccessor.hpp +++ b/src/operation/iRT/source/module/pin_accessor/PinAccessor.hpp @@ -57,7 +57,6 @@ class PinAccessor std::vector convertToPANetList(std::vector& net_list); PANet convertToPANet(Net& net); void setPAComParam(PAModel& pa_model); - void buildBlockTrimRectMap(PAModel& pa_model); void initAccessPointList(PAModel& pa_model); std::vector getLegalShapeList(PAModel& pa_model, int32_t net_idx, PAPin* pa_pin); std::vector getPlanarLegalRectList(PAModel& pa_model, int32_t curr_net_idx, PAPin* pa_pin, std::vector& pin_shape_list); @@ -116,16 +115,14 @@ class PinAccessor double getEstimateViaCost(PABox& pa_box, PANode* start_node, PANode* end_node); void patchPATask(PABox& pa_box, PATask* pa_task); void initSinglePatchTask(PABox& pa_box, PATask* pa_task); - std::vector getPatchViolationList(PABox& pa_box); + std::vector getPatchViolationList(PABox& pa_box, const std::set& check_type_set, const std::vector& check_region_list); bool searchViolation(PABox& pa_box); bool isValidPatchViolation(PABox& pa_box, Violation& violation); std::vector getViolationOverlapRect(PABox& pa_box, Violation& violation); void addViolationToShadow(PABox& pa_box); void patchSingleViolation(PABox& pa_box); std::vector getCandidatePatchList(PABox& pa_box); - void buildSingleViolation(PABox& pa_box, PAPatch& pa_patch); - void updateSingleViolation(PABox& pa_box); - void updateTriedFixViolation(PABox& pa_box); + bool getSolvedStatus(PABox& pa_box, std::vector& origin_patch_violation_list, std::vector& curr_patch_violation_list); void resetSingleViolation(PABox& pa_box); void clearViolationShadow(PABox& pa_box); void updateTaskPatch(PABox& pa_box); @@ -183,8 +180,10 @@ class PinAccessor void printSummary(PAModel& pa_model); void outputNetCSV(PAModel& pa_model); void outputViolationCSV(PAModel& pa_model); - void outputNetJson(PAModel& pa_model); - void outputViolationJson(PAModel& pa_model); + void outputJson(PAModel& pa_model); + std::string outputNetJson(PAModel& pa_model); + std::string outputViolationJson(PAModel& pa_model); + std::string outputSummaryJson(PAModel& pa_model); #endif #if 1 // debug diff --git a/src/operation/iRT/source/module/pin_accessor/framwork.txt b/src/operation/iRT/source/module/pin_accessor/framwork.txt index b87fd58c7ce5fa689205f1e01a415cddefb415d3..a5cb5323c52e2747d25a3b4e39413206bdba3b4f 100644 --- a/src/operation/iRT/source/module/pin_accessor/framwork.txt +++ b/src/operation/iRT/source/module/pin_accessor/framwork.txt @@ -1,6 +1,5 @@ initPAModel:初始化pa_net setPAComParam:设置参数 -buildBlockTrimRectMap:对PinShape在Block很里面的pin,只从最外面生成ap点 initAccessPointList:用boost得到pinshape上的合法区域并生成ap uploadAccessPointList:将中间结果暂时存储至顶层 routePAModel:迭代PAModel diff --git a/src/operation/iRT/source/module/pin_accessor/pa_data_manager/PABox.hpp b/src/operation/iRT/source/module/pin_accessor/pa_data_manager/PABox.hpp index 7a979f4d1efe7761fe26da4d153539e8b7ea8527..6eb113d260419224c1f6dba294bef8ac67f465d6 100644 --- a/src/operation/iRT/source/module/pin_accessor/pa_data_manager/PABox.hpp +++ b/src/operation/iRT/source/module/pin_accessor/pa_data_manager/PABox.hpp @@ -51,6 +51,7 @@ class PABox ScaleAxis& get_box_track_axis() { return _box_track_axis; } std::vector>& get_layer_node_map() { return _layer_node_map; } std::vector& get_layer_shadow_map() { return _layer_shadow_map; } + std::map, std::set>>& get_layer_axis_map() { return _layer_axis_map; } std::map& get_pin_access_point_map() { return _pin_access_point_map; } std::map>>>& get_best_net_task_access_result_map() { return _best_net_task_access_result_map; } std::map>>& get_best_net_task_access_patch_map() { return _best_net_task_access_patch_map; } @@ -87,6 +88,7 @@ class PABox void set_box_track_axis(const ScaleAxis& box_track_axis) { _box_track_axis = box_track_axis; } void set_layer_node_map(const std::vector>& layer_node_map) { _layer_node_map = layer_node_map; } void set_layer_shadow_map(const std::vector& layer_shadow_map) { _layer_shadow_map = layer_shadow_map; } + void set_layer_axis_map(const std::map, std::set>>& layer_axis_map) { _layer_axis_map = layer_axis_map; } void set_pin_access_point_map(const std::map& pin_access_point_map) { _pin_access_point_map = pin_access_point_map; } void set_best_net_task_access_result_map(const std::map>>>& best_net_task_access_result_map) { @@ -141,13 +143,7 @@ class PABox void set_tried_fix_violation_set(const std::set& tried_fix_violation_set) { _tried_fix_violation_set = tried_fix_violation_set; } // single violation Violation& get_curr_patch_violation() { return _curr_patch_violation; } - PAPatch& get_curr_candidate_patch() { return _curr_candidate_patch; } - std::vector& get_curr_patch_violation_list() { return _curr_patch_violation_list; } - bool get_curr_is_solved() const { return _curr_is_solved; } void set_curr_patch_violation(const Violation& curr_patch_violation) { _curr_patch_violation = curr_patch_violation; } - void set_curr_candidate_patch(const PAPatch& curr_candidate_patch) { _curr_candidate_patch = curr_candidate_patch; } - void set_curr_patch_violation_list(const std::vector& curr_patch_violation_list) { _curr_patch_violation_list = curr_patch_violation_list; } - void set_curr_is_solved(const bool curr_is_solved) { _curr_is_solved = curr_is_solved; } #endif private: @@ -166,6 +162,7 @@ class PABox ScaleAxis _box_track_axis; std::vector> _layer_node_map; std::vector _layer_shadow_map; + std::map, std::set>> _layer_axis_map; std::map _pin_access_point_map; std::map>>> _best_net_task_access_result_map; std::map>> _best_net_task_access_patch_map; @@ -193,9 +190,6 @@ class PABox std::set _tried_fix_violation_set; // single violation Violation _curr_patch_violation; - PAPatch _curr_candidate_patch; - std::vector _curr_patch_violation_list; - bool _curr_is_solved = false; #endif }; diff --git a/src/operation/iRT/source/module/pin_accessor/pa_data_manager/PAModel.hpp b/src/operation/iRT/source/module/pin_accessor/pa_data_manager/PAModel.hpp index 4a7b1f771e43d0eca45aacc14880850e6b560393..4693f21862fab8ff9f4b8ef036ce191659c0e49b 100644 --- a/src/operation/iRT/source/module/pin_accessor/pa_data_manager/PAModel.hpp +++ b/src/operation/iRT/source/module/pin_accessor/pa_data_manager/PAModel.hpp @@ -33,7 +33,6 @@ class PAModel // getter PAComParam& get_pa_com_param() { return _pa_com_param; } std::vector& get_pa_net_list() { return _pa_net_list; } - std::map>& get_block_layer_trim_rect_map() { return _block_layer_trim_rect_map; } bool get_initial_routing() const { return _initial_routing; } int32_t get_iter() const { return _iter; } PAIterParam& get_pa_iter_param() { return _pa_iter_param; } @@ -45,10 +44,6 @@ class PAModel // setter void set_pa_com_param(const PAComParam& pa_com_param) { _pa_com_param = pa_com_param; } void set_pa_net_list(const std::vector& pa_net_list) { _pa_net_list = pa_net_list; } - void set_block_layer_trim_rect_map(const std::map>& block_layer_trim_rect_map) - { - _block_layer_trim_rect_map = block_layer_trim_rect_map; - } void set_initial_routing(const bool initial_routing) { _initial_routing = initial_routing; } void set_iter(const int32_t iter) { _iter = iter; } void set_pa_iter_param(const PAIterParam& pa_iter_param) { _pa_iter_param = pa_iter_param; } @@ -67,7 +62,6 @@ class PAModel private: PAComParam _pa_com_param; std::vector _pa_net_list; - std::map> _block_layer_trim_rect_map; bool _initial_routing = true; int32_t _iter = -1; PAIterParam _pa_iter_param; diff --git a/src/operation/iRT/source/module/space_router/CMakeLists.txt b/src/operation/iRT/source/module/space_router/CMakeLists.txt index 898f79760b391412540b3b7be6ffec8280c665f5..4efcca7e525c38f1bca8c7096d6d5108e4cb6e82 100644 --- a/src/operation/iRT/source/module/space_router/CMakeLists.txt +++ b/src/operation/iRT/source/module/space_router/CMakeLists.txt @@ -2,8 +2,8 @@ if(DEBUG_IRT_SPACE_ROUTER) message(STATUS "RT: DEBUG_IRT_SPACE_ROUTER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_SPACE_ROUTER") - set(CMAKE_BUILD_TYPE "Release") + message(STATUS "RT: RELEASE_IRT_SPACE_ROUTER") + set(CMAKE_BUILD_TYPE "Release") endif() add_library(irt_space_router @@ -11,15 +11,15 @@ add_library(irt_space_router ${IRT_MODULE}/space_router/SpaceRouter.cpp ) -target_link_libraries(irt_space_router +target_link_libraries(irt_space_router PUBLIC - irt_data_manager - irt_module - irt_toolkit + irt_data_manager + irt_module + irt_toolkit ) -target_include_directories(irt_space_router +target_include_directories(irt_space_router PUBLIC - ${IRT_MODULE}/space_router/sr_data_manager - ${IRT_MODULE}/space_router + ${IRT_MODULE}/space_router/sr_data_manager + ${IRT_MODULE}/space_router ) diff --git a/src/operation/iRT/source/module/space_router/SpaceRouter.cpp b/src/operation/iRT/source/module/space_router/SpaceRouter.cpp index 22ca26a0345826883d2e700a4ebc40f216d2a596..3eeb00dcbb3c9f18834272a21e3edc550d1a990c 100644 --- a/src/operation/iRT/source/module/space_router/SpaceRouter.cpp +++ b/src/operation/iRT/source/module/space_router/SpaceRouter.cpp @@ -51,6 +51,9 @@ void SpaceRouter::destroyInst() void SpaceRouter::route() { + if (RTDM.getConfig().enable_fast_mode) { + return; + } Monitor monitor; RTLOG.info(Loc::current(), "Starting..."); SRModel sr_model = initSRModel(); @@ -118,6 +121,9 @@ void SpaceRouter::buildLayerNodeMap(SRModel& sr_model) sr_node.set_boundary_wire_unit(gcell_map[x][y].get_boundary_wire_unit()); sr_node.set_internal_wire_unit(gcell_map[x][y].get_internal_wire_unit()); sr_node.set_internal_via_unit(gcell_map[x][y].get_internal_via_unit()); + if (RTUTIL.exist(gcell_map[x][y].get_routing_ignore_net_orient_map(), layer_idx)) { + sr_node.set_ignore_net_orient_map(gcell_map[x][y].get_routing_ignore_net_orient_map()[layer_idx]); + } } } } @@ -177,38 +183,33 @@ void SpaceRouter::routeSRModel(SRModel& sr_model) */ std::vector sr_iter_param_list; // clang-format off - sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 100, 0, 3, overflow_unit, 3); - sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 100, 20, 3, overflow_unit, 3); - sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 100, 40, 3, overflow_unit, 3); - sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 100, 60, 3, overflow_unit, 3); - sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 100, 80, 3, overflow_unit, 3); - sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 100, 0, 3, overflow_unit, 3); - sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 100, 20, 3, overflow_unit, 3); - sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 100, 40, 3, overflow_unit, 3); - sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 100, 60, 3, overflow_unit, 3); - sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 100, 80, 3, overflow_unit, 3); + sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 30, 0, 3, overflow_unit, 3); + sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 30, 10, 3, overflow_unit, 3); + sr_iter_param_list.emplace_back(prefer_wire_unit, via_unit, 30, 20, 3, overflow_unit, 3); // clang-format on initRoutingState(sr_model); for (int32_t i = 0, iter = 1; i < static_cast(sr_iter_param_list.size()); i++, iter++) { Monitor iter_monitor; RTLOG.info(Loc::current(), "***** Begin iteration ", iter, "/", sr_iter_param_list.size(), "(", RTUTIL.getPercentage(iter, sr_iter_param_list.size()), ") *****"); + // debugPlotSRModel(sr_model, "before"); setSRIterParam(sr_model, iter, sr_iter_param_list[i]); initSRBoxMap(sr_model); resetRoutingState(sr_model); buildBoxSchedule(sr_model); splitNetResult(sr_model); + // debugPlotSRModel(sr_model, "middle"); routeSRBoxMap(sr_model); uploadNetResult(sr_model); reviseNodeDemand(sr_model); updateBestResult(sr_model); + // debugPlotSRModel(sr_model, "after"); updateSummary(sr_model); printSummary(sr_model); outputGuide(sr_model); outputNetCSV(sr_model); outputOverflowCSV(sr_model); - outputNetJson(sr_model); - outputOverflowJson(sr_model); + outputJson(sr_model); RTLOG.info(Loc::current(), "***** End Iteration ", iter, "/", sr_iter_param_list.size(), "(", RTUTIL.getPercentage(iter, sr_iter_param_list.size()), ")", iter_monitor.getStatsInfo(), "*****"); if (stopIteration(sr_model)) { @@ -239,31 +240,53 @@ void SpaceRouter::setSRIterParam(SRModel& sr_model, int32_t iter, SRIterParam& s void SpaceRouter::initSRBoxMap(SRModel& sr_model) { ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); - - int32_t x_gcell_num = 0; - for (ScaleGrid& x_grid : gcell_axis.get_x_grid_list()) { - x_gcell_num += x_grid.get_step_num(); - } - int32_t y_gcell_num = 0; - for (ScaleGrid& y_grid : gcell_axis.get_y_grid_list()) { - y_gcell_num += y_grid.get_step_num(); - } - SRIterParam& sr_iter_param = sr_model.get_sr_iter_param(); + int32_t size = sr_iter_param.get_size(); int32_t offset = sr_iter_param.get_offset(); - int32_t x_box_num = static_cast(std::ceil((x_gcell_num - offset) / 1.0 / size)); - int32_t y_box_num = static_cast(std::ceil((y_gcell_num - offset) / 1.0 / size)); - + while (offset >= size) { + offset -= size; + } + std::vector x_scale_list; + { + int32_t x_gcell_num = 0; + for (ScaleGrid& x_grid : gcell_axis.get_x_grid_list()) { + x_gcell_num += x_grid.get_step_num(); + } + x_scale_list.push_back(0); + for (int32_t x_scale = offset; x_scale <= x_gcell_num; x_scale += size) { + x_scale_list.push_back(x_scale); + } + x_scale_list.push_back(x_gcell_num); + std::sort(x_scale_list.begin(), x_scale_list.end()); + x_scale_list.erase(std::unique(x_scale_list.begin(), x_scale_list.end()), x_scale_list.end()); + } + std::vector y_scale_list; + { + int32_t y_gcell_num = 0; + for (ScaleGrid& y_grid : gcell_axis.get_y_grid_list()) { + y_gcell_num += y_grid.get_step_num(); + } + y_scale_list.push_back(0); + for (int32_t y_scale = offset; y_scale <= y_gcell_num; y_scale += size) { + y_scale_list.push_back(y_scale); + } + y_scale_list.push_back(y_gcell_num); + std::sort(y_scale_list.begin(), y_scale_list.end()); + y_scale_list.erase(std::unique(y_scale_list.begin(), y_scale_list.end()), y_scale_list.end()); + } GridMap& sr_box_map = sr_model.get_sr_box_map(); - sr_box_map.init(x_box_num, y_box_num); - + { + int32_t x_box_num = static_cast(x_scale_list.size()) - 1; + int32_t y_box_num = static_cast(y_scale_list.size()) - 1; + sr_box_map.init(x_box_num, y_box_num); + } for (int32_t x = 0; x < sr_box_map.get_x_size(); x++) { for (int32_t y = 0; y < sr_box_map.get_y_size(); y++) { - int32_t grid_ll_x = std::max(offset + x * size, 0); - int32_t grid_ll_y = std::max(offset + y * size, 0); - int32_t grid_ur_x = std::min(offset + (x + 1) * size - 1, x_gcell_num - 1); - int32_t grid_ur_y = std::min(offset + (y + 1) * size - 1, y_gcell_num - 1); + int32_t grid_ll_x = x_scale_list[x]; + int32_t grid_ll_y = y_scale_list[y]; + int32_t grid_ur_x = x_scale_list[x + 1] - 1; + int32_t grid_ur_y = y_scale_list[y + 1] - 1; PlanarRect ll_gcell_rect = RTUTIL.getRealRectByGCell(PlanarCoord(grid_ll_x, grid_ll_y), gcell_axis); PlanarRect ur_gcell_rect = RTUTIL.getRealRectByGCell(PlanarCoord(grid_ur_x, grid_ur_y), gcell_axis); @@ -304,7 +327,9 @@ void SpaceRouter::buildBoxSchedule(SRModel& sr_model) sr_box_id_list.emplace_back(x, y); } } - sr_box_id_list_list.push_back(sr_box_id_list); + if (!sr_box_id_list.empty()) { + sr_box_id_list_list.push_back(sr_box_id_list); + } } } sr_model.set_sr_box_id_list_list(sr_box_id_list_list); @@ -341,7 +366,7 @@ void SpaceRouter::splitNetResult(SRModel& sr_model) } for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { - std::vector*> del_segment_list; + std::set*> del_segment_set; std::vector> new_segment_list; for (Segment* segment : segment_set) { LayerCoord& first_coord = segment->get_first(); @@ -368,7 +393,7 @@ void SpaceRouter::splitNetResult(SRModel& sr_model) x_scale_list.push_back(x_scale); } x_scale_list.push_back(second_x); - del_segment_list.push_back(segment); + del_segment_set.insert(segment); for (size_t i = 1; i < x_scale_list.size(); i++) { new_segment_list.emplace_back(LayerCoord(x_scale_list[i - 1], first_coord.get_y(), first_coord.get_layer_idx()), LayerCoord(x_scale_list[i], first_coord.get_y(), first_coord.get_layer_idx())); @@ -392,14 +417,14 @@ void SpaceRouter::splitNetResult(SRModel& sr_model) y_scale_list.push_back(y_scale); } y_scale_list.push_back(second_y); - del_segment_list.push_back(segment); + del_segment_set.insert(segment); for (size_t i = 1; i < y_scale_list.size(); i++) { new_segment_list.emplace_back(LayerCoord(first_coord.get_x(), y_scale_list[i - 1], first_coord.get_layer_idx()), LayerCoord(first_coord.get_x(), y_scale_list[i], first_coord.get_layer_idx())); } } } - for (Segment* del_segment : del_segment_list) { + for (Segment* del_segment : del_segment_set) { RTDM.updateNetGlobalResultToGCellMap(ChangeType::kDel, net_idx, del_segment); } for (Segment& new_segment : new_segment_list) { @@ -437,7 +462,9 @@ void SpaceRouter::routeSRBoxMap(SRModel& sr_model) buildOrientSupply(sr_model, sr_box); buildOrientDemand(sr_model, sr_box); // debugCheckSRBox(sr_box); + // debugPlotSRBox(sr_box, "before"); routeSRBox(sr_box); + // debugPlotSRBox(sr_box, "after"); } selectBestResult(sr_box); freeSRBox(sr_box); @@ -575,18 +602,8 @@ void SpaceRouter::buildOverflow(SRModel& sr_model, SRBox& sr_box) GridMap& sr_node_map = layer_node_map[layer_idx]; for (int32_t x = box_rect.get_grid_ll_x(); x <= box_rect.get_grid_ur_x(); x++) { for (int32_t y = box_rect.get_grid_ll_y(); y <= box_rect.get_grid_ur_y(); y++) { - double node_overflow = sr_node_map[x][y].getOverflow(); - total_overflow += node_overflow; - if (node_overflow > 0) { - std::set overflow_net_set; - for (auto& [orient, net_set] : sr_node_map[x][y].get_orient_net_map()) { - overflow_net_set.insert(net_set.begin(), net_set.end()); - } - for (auto& [net_idx, orient_set] : sr_node_map[x][y].get_net_orient_map()) { - overflow_net_set.insert(net_idx); - } - overflow_net_set_list.push_back(overflow_net_set); - } + total_overflow += sr_node_map[x][y].getOverflow(); + overflow_net_set_list.push_back(sr_node_map[x][y].getOverflowNetSet()); } } } @@ -662,6 +679,7 @@ void SpaceRouter::buildLayerNodeMap(SRModel& sr_model, SRBox& sr_box) sr_node.set_boundary_wire_unit(top_sr_node_map[sr_node.get_x()][sr_node.get_y()].get_boundary_wire_unit()); sr_node.set_internal_wire_unit(top_sr_node_map[sr_node.get_x()][sr_node.get_y()].get_internal_wire_unit()); sr_node.set_internal_via_unit(top_sr_node_map[sr_node.get_x()][sr_node.get_y()].get_internal_via_unit()); + sr_node.set_ignore_net_orient_map(top_sr_node_map[sr_node.get_x()][sr_node.get_y()].get_ignore_net_orient_map()); } } } @@ -1067,6 +1085,8 @@ SRNode* SpaceRouter::popFromOpenList(SRBox& sr_box) double SpaceRouter::getKnownCost(SRBox& sr_box, SRNode* start_node, SRNode* end_node) { + std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); + bool exist_neighbor = false; for (auto& [orientation, neighbor_ptr] : start_node->get_neighbor_node_map()) { if (neighbor_ptr == end_node) { @@ -1077,22 +1097,27 @@ double SpaceRouter::getKnownCost(SRBox& sr_box, SRNode* start_node, SRNode* end_ if (!exist_neighbor) { RTLOG.error(Loc::current(), "The neighbor not exist!"); } - + Direction direction; + if (start_node->get_layer_idx() == end_node->get_layer_idx()) { + direction = routing_layer_list[start_node->get_layer_idx()].get_prefer_direction(); + } else { + direction = Direction::kProximal; + } double cost = 0; cost += start_node->get_known_cost(); - cost += getNodeCost(sr_box, start_node, RTUTIL.getOrientation(*start_node, *end_node)); - cost += getNodeCost(sr_box, end_node, RTUTIL.getOrientation(*end_node, *start_node)); + cost += getNodeCost(sr_box, start_node, direction); + cost += getNodeCost(sr_box, end_node, direction); cost += getKnownWireCost(sr_box, start_node, end_node); cost += getKnownViaCost(sr_box, start_node, end_node); return cost; } -double SpaceRouter::getNodeCost(SRBox& sr_box, SRNode* curr_node, Orientation orientation) +double SpaceRouter::getNodeCost(SRBox& sr_box, SRNode* curr_node, Direction direction) { double overflow_unit = sr_box.get_sr_iter_param()->get_overflow_unit(); double node_cost = 0; - node_cost += curr_node->getOverflowCost(sr_box.get_curr_sr_task()->get_net_idx(), orientation, overflow_unit); + node_cost += curr_node->getOverflowCost(sr_box.get_curr_sr_task()->get_net_idx(), direction, overflow_unit); return node_cost; } @@ -1173,18 +1198,8 @@ void SpaceRouter::updateOverflow(SRBox& sr_box) GridMap& sr_node_map = layer_node_map[layer_idx]; for (int32_t x = 0; x < sr_node_map.get_x_size(); x++) { for (int32_t y = 0; y < sr_node_map.get_y_size(); y++) { - double node_overflow = sr_node_map[x][y].getOverflow(); - total_overflow += node_overflow; - if (node_overflow > 0) { - std::set overflow_net_set; - for (auto& [orient, net_set] : sr_node_map[x][y].get_orient_net_map()) { - overflow_net_set.insert(net_set.begin(), net_set.end()); - } - for (auto& [net_idx, orient_set] : sr_node_map[x][y].get_net_orient_map()) { - overflow_net_set.insert(net_idx); - } - overflow_net_set_list.push_back(overflow_net_set); - } + total_overflow += sr_node_map[x][y].getOverflow(); + overflow_net_set_list.push_back(sr_node_map[x][y].getOverflowNetSet()); } } } @@ -1369,8 +1384,7 @@ void SpaceRouter::selectBestResult(SRModel& sr_model) outputGuide(sr_model); outputNetCSV(sr_model); outputOverflowCSV(sr_model); - outputNetJson(sr_model); - outputOverflowJson(sr_model); + outputJson(sr_model); RTLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); } @@ -1506,8 +1520,8 @@ void SpaceRouter::updateSummary(SRModel& sr_model) double& total_wire_length = summary.iter_sr_summary_map[sr_model.get_iter()].total_wire_length; std::map& cut_via_num_map = summary.iter_sr_summary_map[sr_model.get_iter()].cut_via_num_map; int32_t& total_via_num = summary.iter_sr_summary_map[sr_model.get_iter()].total_via_num; - std::map>& clock_timing = summary.iter_sr_summary_map[sr_model.get_iter()].clock_timing; - std::map& power_map = summary.iter_sr_summary_map[sr_model.get_iter()].power_map; + std::map>& clock_timing_map = summary.iter_sr_summary_map[sr_model.get_iter()].clock_timing_map; + std::map& type_power_map = summary.iter_sr_summary_map[sr_model.get_iter()].type_power_map; std::vector>& layer_node_map = sr_model.get_layer_node_map(); std::vector& sr_net_list = sr_model.get_sr_net_list(); @@ -1520,8 +1534,8 @@ void SpaceRouter::updateSummary(SRModel& sr_model) total_wire_length = 0; cut_via_num_map.clear(); total_via_num = 0; - clock_timing.clear(); - power_map.clear(); + clock_timing_map.clear(); + type_power_map.clear(); for (int32_t layer_idx = 0; layer_idx < static_cast(layer_node_map.size()); layer_idx++) { GridMap& sr_node_map = layer_node_map[layer_idx]; @@ -1580,7 +1594,7 @@ void SpaceRouter::updateSummary(SRModel& sr_model) routing_segment_list_list[net_idx].emplace_back(first_real_coord, second_real_coord); } } - RTI.updateTimingAndPower(real_pin_coord_map_list, routing_segment_list_list, clock_timing, power_map); + RTI.updateTimingAndPower(real_pin_coord_map_list, routing_segment_list_list, clock_timing_map, type_power_map); } } @@ -1599,8 +1613,8 @@ void SpaceRouter::printSummary(SRModel& sr_model) double& total_wire_length = summary.iter_sr_summary_map[sr_model.get_iter()].total_wire_length; std::map& cut_via_num_map = summary.iter_sr_summary_map[sr_model.get_iter()].cut_via_num_map; int32_t& total_via_num = summary.iter_sr_summary_map[sr_model.get_iter()].total_via_num; - std::map>& clock_timing = summary.iter_sr_summary_map[sr_model.get_iter()].clock_timing; - std::map& power_map = summary.iter_sr_summary_map[sr_model.get_iter()].power_map; + std::map>& clock_timing_map = summary.iter_sr_summary_map[sr_model.get_iter()].clock_timing_map; + std::map& type_power_map = summary.iter_sr_summary_map[sr_model.get_iter()].type_power_map; fort::char_table routing_demand_map_table; { @@ -1659,16 +1673,16 @@ void SpaceRouter::printSummary(SRModel& sr_model) << "tns" << "wns" << "freq" << fort::endr; - for (auto& [clock_name, timing_map] : clock_timing) { + for (auto& [clock_name, timing_map] : clock_timing_map) { timing_table << clock_name << timing_map["TNS"] << timing_map["WNS"] << timing_map["Freq(MHz)"] << fort::endr; } power_table << fort::header << "power_type"; - for (auto& [type, power] : power_map) { + for (auto& [type, power] : type_power_map) { power_table << fort::header << type; } power_table << fort::endr; power_table << "power_value"; - for (auto& [type, power] : power_map) { + for (auto& [type, power] : type_power_map) { power_table << power; } power_table << fort::endr; @@ -1799,54 +1813,64 @@ void SpaceRouter::outputOverflowCSV(SRModel& sr_model) } } -void SpaceRouter::outputNetJson(SRModel& sr_model) +void SpaceRouter::outputJson(SRModel& sr_model) +{ + int32_t enable_notification = RTDM.getConfig().enable_notification; + if (!enable_notification) { + return; + } + std::map json_path_map; + json_path_map["net_map"] = outputNetJson(sr_model); + json_path_map["overflow_map"] = outputOverflowJson(sr_model); + json_path_map["summary"] = outputSummaryJson(sr_model); + RTI.sendNotification("SR", sr_model.get_iter(), json_path_map); +} + +std::string SpaceRouter::outputNetJson(SRModel& sr_model) { Die& die = RTDM.getDatabase().get_die(); ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& net_list = RTDM.getDatabase().get_net_list(); std::string& sr_temp_directory_path = RTDM.getConfig().sr_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector net_json_list; - net_json_list.resize(net_list.size()); - for (Net& net : net_list) { - net_json_list[net.get_net_idx()]["net_name"] = net.get_net_name(); - } - for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { - for (Segment* segment : segment_set) { - PlanarRect first_gcell = RTUTIL.getRealRectByGCell(segment->get_first(), gcell_axis); - PlanarRect second_gcell = RTUTIL.getRealRectByGCell(segment->get_second(), gcell_axis); - if (segment->get_first().get_layer_idx() != segment->get_second().get_layer_idx()) { - net_json_list[net_idx]["result"].push_back({first_gcell.get_ll_x(), first_gcell.get_ll_y(), first_gcell.get_ur_x(), first_gcell.get_ur_y(), - routing_layer_list[segment->get_first().get_layer_idx()].get_layer_name()}); - net_json_list[net_idx]["result"].push_back({second_gcell.get_ll_x(), second_gcell.get_ll_y(), second_gcell.get_ur_x(), second_gcell.get_ur_y(), - routing_layer_list[segment->get_second().get_layer_idx()].get_layer_name()}); - } else { - PlanarRect gcell = RTUTIL.getBoundingBox({first_gcell, second_gcell}); - net_json_list[net_idx]["result"].push_back({gcell.get_ll_x(), gcell.get_ll_y(), gcell.get_ur_x(), gcell.get_ur_y(), - routing_layer_list[segment->get_first().get_layer_idx()].get_layer_name()}); + { + nlohmann::json result_shape_json; + for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { + std::string net_name = net_list[net_idx].get_net_name(); + for (Segment* segment : segment_set) { + PlanarRect first_gcell = RTUTIL.getRealRectByGCell(segment->get_first(), gcell_axis); + PlanarRect second_gcell = RTUTIL.getRealRectByGCell(segment->get_second(), gcell_axis); + if (segment->get_first().get_layer_idx() != segment->get_second().get_layer_idx()) { + result_shape_json["result_shape"][net_name]["path"].push_back({first_gcell.get_ll_x(), first_gcell.get_ll_y(), first_gcell.get_ur_x(), + first_gcell.get_ur_y(), + routing_layer_list[segment->get_first().get_layer_idx()].get_layer_name()}); + result_shape_json["result_shape"][net_name]["path"].push_back({second_gcell.get_ll_x(), second_gcell.get_ll_y(), second_gcell.get_ur_x(), + second_gcell.get_ur_y(), + routing_layer_list[segment->get_second().get_layer_idx()].get_layer_name()}); + } else { + PlanarRect gcell = RTUTIL.getBoundingBox({first_gcell, second_gcell}); + result_shape_json["result_shape"][net_name]["path"].push_back({gcell.get_ll_x(), gcell.get_ll_y(), gcell.get_ur_x(), gcell.get_ur_y(), + routing_layer_list[segment->get_first().get_layer_idx()].get_layer_name()}); + } } } + net_json_list.push_back(result_shape_json); } std::string net_json_file_path = RTUTIL.getString(sr_temp_directory_path, "net_map_", sr_model.get_iter(), ".json"); std::ofstream* net_json_file = RTUTIL.getOutputFileStream(net_json_file_path); (*net_json_file) << net_json_list; RTUTIL.closeFileStream(net_json_file); - RTI.sendNotification(RTUTIL.getString("SR_", sr_model.get_iter(), "_net_map"), net_json_file_path); + return net_json_file_path; } -void SpaceRouter::outputOverflowJson(SRModel& sr_model) +std::string SpaceRouter::outputOverflowJson(SRModel& sr_model) { ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::string& sr_temp_directory_path = RTDM.getConfig().sr_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector>& layer_node_map = sr_model.get_layer_node_map(); std::vector overflow_json_list; for (int32_t layer_idx = 0; layer_idx < static_cast(layer_node_map.size()); layer_idx++) { @@ -1863,13 +1887,377 @@ void SpaceRouter::outputOverflowJson(SRModel& sr_model) std::ofstream* overflow_json_file = RTUTIL.getOutputFileStream(overflow_json_file_path); (*overflow_json_file) << overflow_json_list; RTUTIL.closeFileStream(overflow_json_file); - RTI.sendNotification(RTUTIL.getString("SR_", sr_model.get_iter(), "_net_map"), overflow_json_file_path); + return overflow_json_file_path; +} + +std::string SpaceRouter::outputSummaryJson(SRModel& sr_model) +{ + std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); + std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); + Summary& summary = RTDM.getDatabase().get_summary(); + std::string& sr_temp_directory_path = RTDM.getConfig().sr_temp_directory_path; + + std::map& routing_demand_map = summary.iter_sr_summary_map[sr_model.get_iter()].routing_demand_map; + double& total_demand = summary.iter_sr_summary_map[sr_model.get_iter()].total_demand; + std::map& routing_overflow_map = summary.iter_sr_summary_map[sr_model.get_iter()].routing_overflow_map; + double& total_overflow = summary.iter_sr_summary_map[sr_model.get_iter()].total_overflow; + std::map& routing_wire_length_map = summary.iter_sr_summary_map[sr_model.get_iter()].routing_wire_length_map; + double& total_wire_length = summary.iter_sr_summary_map[sr_model.get_iter()].total_wire_length; + std::map& cut_via_num_map = summary.iter_sr_summary_map[sr_model.get_iter()].cut_via_num_map; + int32_t& total_via_num = summary.iter_sr_summary_map[sr_model.get_iter()].total_via_num; + std::map>& clock_timing_map = summary.iter_sr_summary_map[sr_model.get_iter()].clock_timing_map; + std::map& type_power_map = summary.iter_sr_summary_map[sr_model.get_iter()].type_power_map; + + nlohmann::json summary_json; + summary_json["iter"] = sr_model.get_iter(); + for (auto& [routing_layer_idx, demand] : routing_demand_map) { + summary_json["routing_demand_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = demand; + } + summary_json["total_demand"] = total_demand; + for (auto& [routing_layer_idx, overflow] : routing_overflow_map) { + summary_json["routing_overflow_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = overflow; + } + summary_json["total_overflow"] = total_overflow; + for (auto& [routing_layer_idx, wire_length] : routing_wire_length_map) { + summary_json["routing_wire_length_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = wire_length; + } + summary_json["total_wire_length"] = total_wire_length; + for (auto& [cut_layer_idx, via_num] : cut_via_num_map) { + summary_json["cut_via_num_map"][cut_layer_list[cut_layer_idx].get_layer_name()] = via_num; + } + summary_json["total_via_num"] = total_via_num; + for (auto& [clock_name, timing] : clock_timing_map) { + summary_json["clock_timing_map"]["clock_name"] = clock_name; + summary_json["clock_timing_map"]["timing"] = timing; + } + for (auto& [type, power] : type_power_map) { + summary_json["type_power_map"]["type"] = type; + summary_json["type_power_map"]["power"] = power; + } + + std::string summary_json_file_path = RTUTIL.getString(sr_temp_directory_path, "summary_", sr_model.get_iter(), ".json"); + std::ofstream* summary_json_file = RTUTIL.getOutputFileStream(summary_json_file_path); + (*summary_json_file) << summary_json; + RTUTIL.closeFileStream(summary_json_file); + return summary_json_file_path; } #endif #if 1 // debug +void SpaceRouter::debugPlotSRModel(SRModel& sr_model, std::string flag) +{ + ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); + Die& die = RTDM.getDatabase().get_die(); + std::string& sr_temp_directory_path = RTDM.getConfig().sr_temp_directory_path; + + int32_t point_size = 5; + + GPGDS gp_gds; + + // base_region + { + GPStruct base_region_struct("base_region"); + GPBoundary gp_boundary; + gp_boundary.set_layer_idx(0); + gp_boundary.set_data_type(0); + gp_boundary.set_rect(die.get_real_rect()); + base_region_struct.push(gp_boundary); + gp_gds.addStruct(base_region_struct); + } + + // gcell_axis + { + GPStruct gcell_axis_struct("gcell_axis"); + std::vector gcell_x_list = RTUTIL.getScaleList(die.get_real_ll_x(), die.get_real_ur_x(), gcell_axis.get_x_grid_list()); + std::vector gcell_y_list = RTUTIL.getScaleList(die.get_real_ll_y(), die.get_real_ur_y(), gcell_axis.get_y_grid_list()); + for (int32_t x : gcell_x_list) { + GPPath gp_path; + gp_path.set_layer_idx(0); + gp_path.set_data_type(1); + gp_path.set_segment(x, die.get_real_ll_y(), x, die.get_real_ur_y()); + gcell_axis_struct.push(gp_path); + } + for (int32_t y : gcell_y_list) { + GPPath gp_path; + gp_path.set_layer_idx(0); + gp_path.set_data_type(1); + gp_path.set_segment(die.get_real_ll_x(), y, die.get_real_ur_x(), y); + gcell_axis_struct.push(gp_path); + } + gp_gds.addStruct(gcell_axis_struct); + } + + // fixed_rect + for (auto& [is_routing, layer_net_rect_map] : RTDM.getTypeLayerNetFixedRectMap(die)) { + for (auto& [layer_idx, net_rect_map] : layer_net_rect_map) { + for (auto& [net_idx, rect_set] : net_rect_map) { + GPStruct fixed_rect_struct(RTUTIL.getString("fixed_rect(net_", net_idx, ")")); + for (EXTLayerRect* rect : rect_set) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kShape)); + gp_boundary.set_rect(rect->get_real_rect()); + if (is_routing) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(layer_idx)); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(layer_idx)); + } + fixed_rect_struct.push(gp_boundary); + } + gp_gds.addStruct(fixed_rect_struct); + } + } + } + + // access_point + for (auto& [net_idx, access_point_set] : RTDM.getNetAccessPointMap(die)) { + GPStruct access_point_struct(RTUTIL.getString("access_point(net_", net_idx, ")")); + for (AccessPoint* access_point : access_point_set) { + int32_t x = access_point->get_real_x(); + int32_t y = access_point->get_real_y(); + + GPBoundary access_point_boundary; + access_point_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(access_point->get_layer_idx())); + access_point_boundary.set_data_type(static_cast(GPDataType::kAccessPoint)); + access_point_boundary.set_rect(x - point_size, y - point_size, x + point_size, y + point_size); + access_point_struct.push(access_point_boundary); + } + gp_gds.addStruct(access_point_struct); + } + + // routing result + for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { + GPStruct global_result_struct(RTUTIL.getString("global_result(net_", net_idx, ")")); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetGlobalShapeList(net_idx, *segment)) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kGlobalPath)); + gp_boundary.set_rect(net_shape.get_rect()); + if (net_shape.get_is_routing()) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(net_shape.get_layer_idx())); + } + global_result_struct.push(gp_boundary); + } + } + gp_gds.addStruct(global_result_struct); + } + + // routing result + for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { + GPStruct detailed_result_struct(RTUTIL.getString("detailed_result(net_", net_idx, ")")); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kShape)); + gp_boundary.set_rect(net_shape.get_rect()); + if (net_shape.get_is_routing()) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(net_shape.get_layer_idx())); + } + detailed_result_struct.push(gp_boundary); + } + } + gp_gds.addStruct(detailed_result_struct); + } + + // routing patch + for (auto& [net_idx, patch_set] : RTDM.getNetDetailedPatchMap(die)) { + GPStruct detailed_patch_struct(RTUTIL.getString("detailed_patch(net_", net_idx, ")")); + for (EXTLayerRect* patch : patch_set) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kShape)); + gp_boundary.set_rect(patch->get_real_rect()); + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(patch->get_layer_idx())); + detailed_patch_struct.push(gp_boundary); + } + gp_gds.addStruct(detailed_patch_struct); + } + + // layer_node_map + { + std::vector>& layer_node_map = sr_model.get_layer_node_map(); + // sr_node_map + { + GPStruct sr_node_map_struct("sr_node_map"); + for (GridMap& sr_node_map : layer_node_map) { + for (int32_t grid_x = 0; grid_x < sr_node_map.get_x_size(); grid_x++) { + for (int32_t grid_y = 0; grid_y < sr_node_map.get_y_size(); grid_y++) { + SRNode& sr_node = sr_node_map[grid_x][grid_y]; + PlanarRect real_rect = RTUTIL.getRealRectByGCell(sr_node.get_planar_coord(), gcell_axis); + int32_t y_reduced_span = std::max(1, real_rect.getYSpan() / 12); + int32_t y = real_rect.get_ur_y(); + + y -= y_reduced_span; + GPText gp_text_node_real_coord; + gp_text_node_real_coord.set_coord(real_rect.get_ll_x(), y); + gp_text_node_real_coord.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_node_real_coord.set_message(RTUTIL.getString("(", sr_node.get_x(), " , ", sr_node.get_y(), " , ", sr_node.get_layer_idx(), ")")); + gp_text_node_real_coord.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_node_real_coord.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_node_real_coord); + + y -= y_reduced_span; + GPText gp_text_node_grid_coord; + gp_text_node_grid_coord.set_coord(real_rect.get_ll_x(), y); + gp_text_node_grid_coord.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_node_grid_coord.set_message(RTUTIL.getString("(", grid_x, " , ", grid_y, " , ", sr_node.get_layer_idx(), ")")); + gp_text_node_grid_coord.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_node_grid_coord.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_node_grid_coord); + + y -= y_reduced_span; + GPText gp_text_orient_supply_map; + gp_text_orient_supply_map.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_supply_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_orient_supply_map.set_message("orient_supply_map: "); + gp_text_orient_supply_map.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_orient_supply_map.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_orient_supply_map); + + if (!sr_node.get_orient_supply_map().empty()) { + y -= y_reduced_span; + GPText gp_text_orient_supply_map_info; + gp_text_orient_supply_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_supply_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string orient_supply_map_info_message = "--"; + for (auto& [orient, supply] : sr_node.get_orient_supply_map()) { + orient_supply_map_info_message += RTUTIL.getString("(", GetOrientationName()(orient), ",", supply, ")"); + } + gp_text_orient_supply_map_info.set_message(orient_supply_map_info_message); + gp_text_orient_supply_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_orient_supply_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_orient_supply_map_info); + } + + y -= y_reduced_span; + GPText gp_text_ignore_net_orient_map; + gp_text_ignore_net_orient_map.set_coord(real_rect.get_ll_x(), y); + gp_text_ignore_net_orient_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_ignore_net_orient_map.set_message("ignore_net_orient_map: "); + gp_text_ignore_net_orient_map.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_ignore_net_orient_map.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_ignore_net_orient_map); + + if (!sr_node.get_ignore_net_orient_map().empty()) { + y -= y_reduced_span; + GPText gp_text_ignore_net_orient_map_info; + gp_text_ignore_net_orient_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_ignore_net_orient_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string ignore_net_orient_map_info_message = "--"; + for (auto& [net_idx, orient_set] : sr_node.get_ignore_net_orient_map()) { + ignore_net_orient_map_info_message += RTUTIL.getString("(", net_idx); + for (Orientation orient : orient_set) { + ignore_net_orient_map_info_message += RTUTIL.getString(",", GetOrientationName()(orient)); + } + ignore_net_orient_map_info_message += RTUTIL.getString(")"); + } + gp_text_ignore_net_orient_map_info.set_message(ignore_net_orient_map_info_message); + gp_text_ignore_net_orient_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_ignore_net_orient_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_ignore_net_orient_map_info); + } + + y -= y_reduced_span; + GPText gp_text_orient_net_map; + gp_text_orient_net_map.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_net_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_orient_net_map.set_message("orient_net_map: "); + gp_text_orient_net_map.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_orient_net_map.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_orient_net_map); + + if (!sr_node.get_orient_net_map().empty()) { + y -= y_reduced_span; + GPText gp_text_orient_net_map_info; + gp_text_orient_net_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_net_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string orient_net_map_info_message = "--"; + for (auto& [orient, net_set] : sr_node.get_orient_net_map()) { + orient_net_map_info_message += RTUTIL.getString("(", GetOrientationName()(orient)); + for (int32_t net_idx : net_set) { + orient_net_map_info_message += RTUTIL.getString(",", net_idx); + } + orient_net_map_info_message += RTUTIL.getString(")"); + } + gp_text_orient_net_map_info.set_message(orient_net_map_info_message); + gp_text_orient_net_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_orient_net_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_orient_net_map_info); + } + + y -= y_reduced_span; + GPText gp_text_net_orient_map; + gp_text_net_orient_map.set_coord(real_rect.get_ll_x(), y); + gp_text_net_orient_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_net_orient_map.set_message("net_orient_map: "); + gp_text_net_orient_map.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_net_orient_map.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_net_orient_map); + + if (!sr_node.get_net_orient_map().empty()) { + y -= y_reduced_span; + GPText gp_text_net_orient_map_info; + gp_text_net_orient_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_net_orient_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string net_orient_map_info_message = "--"; + for (auto& [net_idx, orient_set] : sr_node.get_net_orient_map()) { + net_orient_map_info_message += RTUTIL.getString("(", net_idx); + for (Orientation orient : orient_set) { + net_orient_map_info_message += RTUTIL.getString(",", GetOrientationName()(orient)); + } + net_orient_map_info_message += RTUTIL.getString(")"); + } + gp_text_net_orient_map_info.set_message(net_orient_map_info_message); + gp_text_net_orient_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_net_orient_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_net_orient_map_info); + } + + y -= y_reduced_span; + GPText gp_text_overflow; + gp_text_overflow.set_coord(real_rect.get_ll_x(), y); + gp_text_overflow.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_overflow.set_message(RTUTIL.getString("overflow: ", sr_node.getOverflow())); + gp_text_overflow.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_overflow.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_overflow); + } + } + } + gp_gds.addStruct(sr_node_map_struct); + } + // overflow + { + GPStruct overflow_struct("overflow"); + for (GridMap& sr_node_map : layer_node_map) { + for (int32_t grid_x = 0; grid_x < sr_node_map.get_x_size(); grid_x++) { + for (int32_t grid_y = 0; grid_y < sr_node_map.get_y_size(); grid_y++) { + SRNode& sr_node = sr_node_map[grid_x][grid_y]; + if (sr_node.getOverflow() <= 0) { + continue; + } + PlanarRect real_rect = RTUTIL.getRealRectByGCell(sr_node.get_planar_coord(), gcell_axis); + + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kOverflow)); + gp_boundary.set_rect(real_rect); + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + overflow_struct.push(gp_boundary); + } + } + } + gp_gds.addStruct(overflow_struct); + } + } + + std::string gds_file_path = RTUTIL.getString(sr_temp_directory_path, flag, "_sr_model.gds"); + RTGP.plot(gp_gds, gds_file_path); +} + void SpaceRouter::debugCheckSRBox(SRBox& sr_box) { SRBoxId& sr_box_id = sr_box.get_sr_box_id(); @@ -1902,6 +2290,299 @@ void SpaceRouter::debugCheckSRBox(SRBox& sr_box) } } +void SpaceRouter::debugPlotSRBox(SRBox& sr_box, std::string flag) +{ + ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); + std::string& sr_temp_directory_path = RTDM.getConfig().sr_temp_directory_path; + + PlanarRect box_real_rect = sr_box.get_box_rect().get_real_rect(); + + int32_t point_size = 5; + + GPGDS gp_gds; + + // base_region + { + GPStruct base_region_struct("base_region"); + GPBoundary gp_boundary; + gp_boundary.set_layer_idx(0); + gp_boundary.set_data_type(0); + gp_boundary.set_rect(box_real_rect); + base_region_struct.push(gp_boundary); + gp_gds.addStruct(base_region_struct); + } + + // gcell_axis + { + GPStruct gcell_axis_struct("gcell_axis"); + for (int32_t x : RTUTIL.getScaleList(box_real_rect.get_ll_x(), box_real_rect.get_ur_x(), gcell_axis.get_x_grid_list())) { + GPPath gp_path; + gp_path.set_layer_idx(0); + gp_path.set_data_type(1); + gp_path.set_segment(x, box_real_rect.get_ll_y(), x, box_real_rect.get_ur_y()); + gcell_axis_struct.push(gp_path); + } + for (int32_t y : RTUTIL.getScaleList(box_real_rect.get_ll_y(), box_real_rect.get_ur_y(), gcell_axis.get_y_grid_list())) { + GPPath gp_path; + gp_path.set_layer_idx(0); + gp_path.set_data_type(1); + gp_path.set_segment(box_real_rect.get_ll_x(), y, box_real_rect.get_ur_x(), y); + gcell_axis_struct.push(gp_path); + } + gp_gds.addStruct(gcell_axis_struct); + } + + // fixed_rect + for (auto& [is_routing, layer_net_rect_map] : RTDM.getTypeLayerNetFixedRectMap(sr_box.get_box_rect())) { + for (auto& [layer_idx, net_rect_map] : layer_net_rect_map) { + for (auto& [net_idx, rect_set] : net_rect_map) { + GPStruct fixed_rect_struct(RTUTIL.getString("fixed_rect(net_", net_idx, ")")); + for (EXTLayerRect* rect : rect_set) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kShape)); + gp_boundary.set_rect(rect->get_real_rect()); + if (is_routing) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(layer_idx)); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(layer_idx)); + } + fixed_rect_struct.push(gp_boundary); + } + gp_gds.addStruct(fixed_rect_struct); + } + } + } + + // access_point + for (auto& [net_idx, access_point_set] : RTDM.getNetAccessPointMap(sr_box.get_box_rect())) { + GPStruct access_point_struct(RTUTIL.getString("access_point(net_", net_idx, ")")); + for (AccessPoint* access_point : access_point_set) { + int32_t x = access_point->get_real_x(); + int32_t y = access_point->get_real_y(); + + GPBoundary access_point_boundary; + access_point_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(access_point->get_layer_idx())); + access_point_boundary.set_data_type(static_cast(GPDataType::kAccessPoint)); + access_point_boundary.set_rect(x - point_size, y - point_size, x + point_size, y + point_size); + access_point_struct.push(access_point_boundary); + } + gp_gds.addStruct(access_point_struct); + } + + // net_detailed_result + for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(sr_box.get_box_rect())) { + GPStruct detailed_result_struct(RTUTIL.getString("detailed_result(net_", net_idx, ")")); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kShape)); + gp_boundary.set_rect(net_shape.get_rect()); + if (net_shape.get_is_routing()) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(net_shape.get_layer_idx())); + } + detailed_result_struct.push(gp_boundary); + } + } + gp_gds.addStruct(detailed_result_struct); + } + + // net_detailed_patch + for (auto& [net_idx, patch_set] : RTDM.getNetDetailedPatchMap(sr_box.get_box_rect())) { + GPStruct detailed_patch_struct(RTUTIL.getString("detailed_patch(net_", net_idx, ")")); + for (EXTLayerRect* patch : patch_set) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kShape)); + gp_boundary.set_rect(patch->get_real_rect()); + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(patch->get_layer_idx())); + detailed_patch_struct.push(gp_boundary); + } + gp_gds.addStruct(detailed_patch_struct); + } + + // layer_node_map + { + std::vector>& layer_node_map = sr_box.get_layer_node_map(); + // sr_node_map + { + GPStruct sr_node_map_struct("sr_node_map"); + for (GridMap& sr_node_map : layer_node_map) { + for (int32_t grid_x = 0; grid_x < sr_node_map.get_x_size(); grid_x++) { + for (int32_t grid_y = 0; grid_y < sr_node_map.get_y_size(); grid_y++) { + SRNode& sr_node = sr_node_map[grid_x][grid_y]; + PlanarRect real_rect = RTUTIL.getRealRectByGCell(sr_node.get_planar_coord(), gcell_axis); + int32_t y_reduced_span = std::max(1, real_rect.getYSpan() / 12); + int32_t y = real_rect.get_ur_y(); + + y -= y_reduced_span; + GPText gp_text_node_real_coord; + gp_text_node_real_coord.set_coord(real_rect.get_ll_x(), y); + gp_text_node_real_coord.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_node_real_coord.set_message(RTUTIL.getString("(", sr_node.get_x(), " , ", sr_node.get_y(), " , ", sr_node.get_layer_idx(), ")")); + gp_text_node_real_coord.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_node_real_coord.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_node_real_coord); + + y -= y_reduced_span; + GPText gp_text_node_grid_coord; + gp_text_node_grid_coord.set_coord(real_rect.get_ll_x(), y); + gp_text_node_grid_coord.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_node_grid_coord.set_message(RTUTIL.getString("(", grid_x, " , ", grid_y, " , ", sr_node.get_layer_idx(), ")")); + gp_text_node_grid_coord.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_node_grid_coord.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_node_grid_coord); + + y -= y_reduced_span; + GPText gp_text_orient_supply_map; + gp_text_orient_supply_map.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_supply_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_orient_supply_map.set_message("orient_supply_map: "); + gp_text_orient_supply_map.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_orient_supply_map.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_orient_supply_map); + + if (!sr_node.get_orient_supply_map().empty()) { + y -= y_reduced_span; + GPText gp_text_orient_supply_map_info; + gp_text_orient_supply_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_supply_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string orient_supply_map_info_message = "--"; + for (auto& [orient, supply] : sr_node.get_orient_supply_map()) { + orient_supply_map_info_message += RTUTIL.getString("(", GetOrientationName()(orient), ",", supply, ")"); + } + gp_text_orient_supply_map_info.set_message(orient_supply_map_info_message); + gp_text_orient_supply_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_orient_supply_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_orient_supply_map_info); + } + + y -= y_reduced_span; + GPText gp_text_ignore_net_orient_map; + gp_text_ignore_net_orient_map.set_coord(real_rect.get_ll_x(), y); + gp_text_ignore_net_orient_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_ignore_net_orient_map.set_message("ignore_net_orient_map: "); + gp_text_ignore_net_orient_map.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_ignore_net_orient_map.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_ignore_net_orient_map); + + if (!sr_node.get_ignore_net_orient_map().empty()) { + y -= y_reduced_span; + GPText gp_text_ignore_net_orient_map_info; + gp_text_ignore_net_orient_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_ignore_net_orient_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string ignore_net_orient_map_info_message = "--"; + for (auto& [net_idx, orient_set] : sr_node.get_ignore_net_orient_map()) { + ignore_net_orient_map_info_message += RTUTIL.getString("(", net_idx); + for (Orientation orient : orient_set) { + ignore_net_orient_map_info_message += RTUTIL.getString(",", GetOrientationName()(orient)); + } + ignore_net_orient_map_info_message += RTUTIL.getString(")"); + } + gp_text_ignore_net_orient_map_info.set_message(ignore_net_orient_map_info_message); + gp_text_ignore_net_orient_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_ignore_net_orient_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_ignore_net_orient_map_info); + } + + y -= y_reduced_span; + GPText gp_text_orient_net_map; + gp_text_orient_net_map.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_net_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_orient_net_map.set_message("orient_net_map: "); + gp_text_orient_net_map.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_orient_net_map.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_orient_net_map); + + if (!sr_node.get_orient_net_map().empty()) { + y -= y_reduced_span; + GPText gp_text_orient_net_map_info; + gp_text_orient_net_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_net_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string orient_net_map_info_message = "--"; + for (auto& [orient, net_set] : sr_node.get_orient_net_map()) { + orient_net_map_info_message += RTUTIL.getString("(", GetOrientationName()(orient)); + for (int32_t net_idx : net_set) { + orient_net_map_info_message += RTUTIL.getString(",", net_idx); + } + orient_net_map_info_message += RTUTIL.getString(")"); + } + gp_text_orient_net_map_info.set_message(orient_net_map_info_message); + gp_text_orient_net_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_orient_net_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_orient_net_map_info); + } + + y -= y_reduced_span; + GPText gp_text_net_orient_map; + gp_text_net_orient_map.set_coord(real_rect.get_ll_x(), y); + gp_text_net_orient_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_net_orient_map.set_message("net_orient_map: "); + gp_text_net_orient_map.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_net_orient_map.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_net_orient_map); + + if (!sr_node.get_net_orient_map().empty()) { + y -= y_reduced_span; + GPText gp_text_net_orient_map_info; + gp_text_net_orient_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_net_orient_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string net_orient_map_info_message = "--"; + for (auto& [net_idx, orient_set] : sr_node.get_net_orient_map()) { + net_orient_map_info_message += RTUTIL.getString("(", net_idx); + for (Orientation orient : orient_set) { + net_orient_map_info_message += RTUTIL.getString(",", GetOrientationName()(orient)); + } + net_orient_map_info_message += RTUTIL.getString(")"); + } + gp_text_net_orient_map_info.set_message(net_orient_map_info_message); + gp_text_net_orient_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_net_orient_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_net_orient_map_info); + } + + y -= y_reduced_span; + GPText gp_text_overflow; + gp_text_overflow.set_coord(real_rect.get_ll_x(), y); + gp_text_overflow.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_overflow.set_message(RTUTIL.getString("overflow: ", sr_node.getOverflow())); + gp_text_overflow.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + gp_text_overflow.set_presentation(GPTextPresentation::kLeftMiddle); + sr_node_map_struct.push(gp_text_overflow); + } + } + } + gp_gds.addStruct(sr_node_map_struct); + } + // overflow + { + GPStruct overflow_struct("overflow"); + for (GridMap& sr_node_map : layer_node_map) { + for (int32_t grid_x = 0; grid_x < sr_node_map.get_x_size(); grid_x++) { + for (int32_t grid_y = 0; grid_y < sr_node_map.get_y_size(); grid_y++) { + SRNode& sr_node = sr_node_map[grid_x][grid_y]; + if (sr_node.getOverflow() <= 0) { + continue; + } + PlanarRect real_rect = RTUTIL.getRealRectByGCell(sr_node.get_planar_coord(), gcell_axis); + + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kOverflow)); + gp_boundary.set_rect(real_rect); + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(sr_node.get_layer_idx())); + overflow_struct.push(gp_boundary); + } + } + } + gp_gds.addStruct(overflow_struct); + } + } + + std::string gds_file_path + = RTUTIL.getString(sr_temp_directory_path, flag, "_sr_box_", sr_box.get_sr_box_id().get_x(), "_", sr_box.get_sr_box_id().get_y(), ".gds"); + RTGP.plot(gp_gds, gds_file_path); +} + #endif } // namespace irt diff --git a/src/operation/iRT/source/module/space_router/SpaceRouter.hpp b/src/operation/iRT/source/module/space_router/SpaceRouter.hpp index 461a778baf25080e3f7f527aa7b69da089bbbc09..4983e0c3c629a95a3704a1894a3dfffd275cd365 100644 --- a/src/operation/iRT/source/module/space_router/SpaceRouter.hpp +++ b/src/operation/iRT/source/module/space_router/SpaceRouter.hpp @@ -89,7 +89,7 @@ class SpaceRouter void pushToOpenList(SRBox& sr_box, SRNode* curr_node); SRNode* popFromOpenList(SRBox& sr_box); double getKnownCost(SRBox& sr_box, SRNode* start_node, SRNode* end_node); - double getNodeCost(SRBox& sr_box, SRNode* curr_node, Orientation orientation); + double getNodeCost(SRBox& sr_box, SRNode* curr_node, Direction direction); double getKnownWireCost(SRBox& sr_box, SRNode* start_node, SRNode* end_node); double getKnownViaCost(SRBox& sr_box, SRNode* start_node, SRNode* end_node); double getEstimateCostToEnd(SRBox& sr_box, SRNode* curr_node); @@ -120,12 +120,16 @@ class SpaceRouter void outputGuide(SRModel& sr_model); void outputNetCSV(SRModel& sr_model); void outputOverflowCSV(SRModel& sr_model); - void outputNetJson(SRModel& sr_model); - void outputOverflowJson(SRModel& sr_model); + void outputJson(SRModel& sr_model); + std::string outputNetJson(SRModel& sr_model); + std::string outputOverflowJson(SRModel& sr_model); + std::string outputSummaryJson(SRModel& sr_model); #endif #if 1 // debug + void debugPlotSRModel(SRModel& sr_model, std::string flag); void debugCheckSRBox(SRBox& sr_box); + void debugPlotSRBox(SRBox& sr_box, std::string flag); #endif }; diff --git a/src/operation/iRT/source/module/space_router/sr_data_manager/SRNode.hpp b/src/operation/iRT/source/module/space_router/sr_data_manager/SRNode.hpp index 148f98b3032e69ae434c13e7824dc0a40a441a8a..9db971ae3a720475737fe5d2bcff2950a0d8f113 100644 --- a/src/operation/iRT/source/module/space_router/sr_data_manager/SRNode.hpp +++ b/src/operation/iRT/source/module/space_router/sr_data_manager/SRNode.hpp @@ -44,6 +44,7 @@ class SRNode : public LayerCoord double get_internal_via_unit() const { return _internal_via_unit; } std::map& get_neighbor_node_map() { return _neighbor_node_map; } std::map& get_orient_supply_map() { return _orient_supply_map; } + std::map>& get_ignore_net_orient_map() { return _ignore_net_orient_map; } std::map>& get_orient_net_map() { return _orient_net_map; } std::map>& get_net_orient_map() { return _net_orient_map; } // setter @@ -52,6 +53,7 @@ class SRNode : public LayerCoord void set_internal_via_unit(const double internal_via_unit) { _internal_via_unit = internal_via_unit; } void set_neighbor_node_map(const std::map& neighbor_node_map) { _neighbor_node_map = neighbor_node_map; } void set_orient_supply_map(const std::map& orient_supply_map) { _orient_supply_map = orient_supply_map; } + void set_ignore_net_orient_map(const std::map>& ignore_net_orient_map) { _ignore_net_orient_map = ignore_net_orient_map; } void set_orient_net_map(const std::map>& orient_net_map) { _orient_net_map = orient_net_map; } void set_net_orient_map(const std::map>& net_orient_map) { _net_orient_map = net_orient_map; } // function @@ -63,41 +65,68 @@ class SRNode : public LayerCoord } return neighbor_node; } - double getOverflowCost(int32_t curr_net_idx, Orientation orientation, double overflow_unit) + double getOverflowCost(int32_t net_idx, Direction direction, double overflow_unit) { if (!validDemandUnit()) { RTLOG.error(Loc::current(), "The demand unit is error!"); } + std::map> orient_net_map = _orient_net_map; + std::map> net_orient_map = _net_orient_map; + if (direction == Direction::kHorizontal) { + for (Orientation orient : {Orientation::kEast, Orientation::kWest}) { + orient_net_map[orient].insert(net_idx); + net_orient_map[net_idx].insert(orient); + } + } else if (direction == Direction::kVertical) { + for (Orientation orient : {Orientation::kSouth, Orientation::kNorth}) { + orient_net_map[orient].insert(net_idx); + net_orient_map[net_idx].insert(orient); + } + } else if (direction == Direction::kProximal) { + for (Orientation orient : {Orientation::kAbove, Orientation::kBelow}) { + orient_net_map[orient].insert(net_idx); + net_orient_map[net_idx].insert(orient); + } + } else { + RTLOG.error(Loc::current(), "The direction is error!"); + } double boundary_overflow = 0; - if (orientation == Orientation::kEast || orientation == Orientation::kWest || orientation == Orientation::kSouth || orientation == Orientation::kNorth) { + for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { double boundary_demand = 0; - if (RTUTIL.exist(_orient_net_map, orientation)) { - std::set& net_set = _orient_net_map[orientation]; - boundary_demand += (static_cast(net_set.size()) * _boundary_wire_unit); - if (RTUTIL.exist(net_set, curr_net_idx)) { - boundary_demand -= _boundary_wire_unit; + if (RTUTIL.exist(orient_net_map, orient)) { + for (int32_t demand_net_idx : orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + boundary_demand += _boundary_wire_unit; } } double boundary_supply = 0; - if (RTUTIL.exist(_orient_supply_map, orientation)) { - boundary_supply = (_orient_supply_map[orientation] * _boundary_wire_unit); + if (RTUTIL.exist(_orient_supply_map, orient)) { + boundary_supply = (_orient_supply_map[orient] * _boundary_wire_unit); } - boundary_overflow = calcCost(boundary_demand + _boundary_wire_unit, boundary_supply); + boundary_overflow += calcCost(boundary_demand, boundary_supply); } double internal_overflow = 0; { double internal_demand = 0; - for (auto& [orient, net_set] : _orient_net_map) { - if (orient == Orientation::kAbove || orient == Orientation::kBelow) { - continue; - } - internal_demand += (static_cast(net_set.size()) * _internal_wire_unit); - if (RTUTIL.exist(net_set, curr_net_idx)) { - internal_demand -= _internal_wire_unit; + for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { + if (RTUTIL.exist(orient_net_map, orient)) { + for (int32_t demand_net_idx : orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + internal_demand += _internal_wire_unit; + } } } - for (auto& [net_idx, orient_set] : _net_orient_map) { - if (net_idx == curr_net_idx) { + for (auto& [net_idx, orient_set] : net_orient_map) { + if (RTUTIL.exist(_ignore_net_orient_map, net_idx) + && (RTUTIL.exist(_ignore_net_orient_map[net_idx], Orientation::kAbove) || RTUTIL.exist(_ignore_net_orient_map[net_idx], Orientation::kBelow))) { + continue; + } + if (RTUTIL.exist(orient_set, Orientation::kEast) || RTUTIL.exist(orient_set, Orientation::kWest) || RTUTIL.exist(orient_set, Orientation::kSouth) + || RTUTIL.exist(orient_set, Orientation::kNorth)) { continue; } if (RTUTIL.exist(orient_set, Orientation::kAbove) || RTUTIL.exist(orient_set, Orientation::kBelow)) { @@ -108,11 +137,7 @@ class SRNode : public LayerCoord for (auto& [orient, supply] : _orient_supply_map) { internal_supply += (supply * _internal_wire_unit); } - if (orientation == Orientation::kEast || orientation == Orientation::kWest || orientation == Orientation::kSouth || orientation == Orientation::kNorth) { - internal_overflow = calcCost(internal_demand + _internal_wire_unit, internal_supply); - } else if (orientation == Orientation::kAbove || orientation == Orientation::kBelow) { - internal_overflow = calcCost(internal_demand + _internal_via_unit, internal_supply); - } + internal_overflow += calcCost(internal_demand, internal_supply); } double cost = 0; cost += (overflow_unit * (boundary_overflow + internal_overflow)); @@ -137,9 +162,9 @@ class SRNode : public LayerCoord if (demand == supply) { cost = 1; } else if (demand > supply) { - cost = std::pow(demand - supply + 1, 2); + cost = std::pow(demand - supply + 1, 4); } else if (demand < supply) { - cost = std::pow(demand / supply, 2); + cost = std::pow(demand / supply, 4); } return cost; } @@ -161,6 +186,10 @@ class SRNode : public LayerCoord } } for (auto& [net_idx, orient_set] : _net_orient_map) { + if (RTUTIL.exist(orient_set, Orientation::kEast) || RTUTIL.exist(orient_set, Orientation::kWest) || RTUTIL.exist(orient_set, Orientation::kSouth) + || RTUTIL.exist(orient_set, Orientation::kNorth)) { + continue; + } if (RTUTIL.exist(orient_set, Orientation::kAbove) || RTUTIL.exist(orient_set, Orientation::kBelow)) { internal_demand += _internal_via_unit; } @@ -176,7 +205,12 @@ class SRNode : public LayerCoord for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { double boundary_demand = 0; if (RTUTIL.exist(_orient_net_map, orient)) { - boundary_demand = (static_cast(_orient_net_map[orient].size()) * _boundary_wire_unit); + for (int32_t demand_net_idx : _orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + boundary_demand += _boundary_wire_unit; + } } double boundary_supply = 0; if (RTUTIL.exist(_orient_supply_map, orient)) { @@ -189,10 +223,23 @@ class SRNode : public LayerCoord double internal_demand = 0; for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { if (RTUTIL.exist(_orient_net_map, orient)) { - internal_demand += (static_cast(_orient_net_map[orient].size()) * _internal_wire_unit); + for (int32_t demand_net_idx : _orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + internal_demand += _internal_wire_unit; + } } } for (auto& [net_idx, orient_set] : _net_orient_map) { + if (RTUTIL.exist(_ignore_net_orient_map, net_idx) + && (RTUTIL.exist(_ignore_net_orient_map[net_idx], Orientation::kAbove) || RTUTIL.exist(_ignore_net_orient_map[net_idx], Orientation::kBelow))) { + continue; + } + if (RTUTIL.exist(orient_set, Orientation::kEast) || RTUTIL.exist(orient_set, Orientation::kWest) || RTUTIL.exist(orient_set, Orientation::kSouth) + || RTUTIL.exist(orient_set, Orientation::kNorth)) { + continue; + } if (RTUTIL.exist(orient_set, Orientation::kAbove) || RTUTIL.exist(orient_set, Orientation::kBelow)) { internal_demand += _internal_via_unit; } @@ -205,6 +252,67 @@ class SRNode : public LayerCoord } return (boundary_overflow + internal_overflow); } + std::set getOverflowNetSet() + { + if (!validDemandUnit()) { + RTLOG.error(Loc::current(), "The demand unit is error!"); + } + std::set overflow_net_set; + for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { + double boundary_demand = 0; + if (RTUTIL.exist(_orient_net_map, orient)) { + for (int32_t demand_net_idx : _orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + boundary_demand += _boundary_wire_unit; + } + } + double boundary_supply = 0; + if (RTUTIL.exist(_orient_supply_map, orient)) { + boundary_supply = (_orient_supply_map[orient] * _boundary_wire_unit); + } + if (boundary_demand - boundary_supply > 0) { + overflow_net_set.insert(_orient_net_map[orient].begin(), _orient_net_map[orient].end()); + } + } + { + double internal_demand = 0; + for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { + if (RTUTIL.exist(_orient_net_map, orient)) { + for (int32_t demand_net_idx : _orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + internal_demand += _internal_wire_unit; + } + } + } + for (auto& [net_idx, orient_set] : _net_orient_map) { + if (RTUTIL.exist(_ignore_net_orient_map, net_idx) + && (RTUTIL.exist(_ignore_net_orient_map[net_idx], Orientation::kAbove) || RTUTIL.exist(_ignore_net_orient_map[net_idx], Orientation::kBelow))) { + continue; + } + if (RTUTIL.exist(orient_set, Orientation::kEast) || RTUTIL.exist(orient_set, Orientation::kWest) || RTUTIL.exist(orient_set, Orientation::kSouth) + || RTUTIL.exist(orient_set, Orientation::kNorth)) { + continue; + } + if (RTUTIL.exist(orient_set, Orientation::kAbove) || RTUTIL.exist(orient_set, Orientation::kBelow)) { + internal_demand += _internal_via_unit; + } + } + double internal_supply = 0; + for (auto& [orient, supply] : _orient_supply_map) { + internal_supply += (supply * _internal_wire_unit); + } + if (internal_demand - internal_supply > 0) { + for (auto& [net_idx, orient_set] : _net_orient_map) { + overflow_net_set.insert(net_idx); + } + } + } + return overflow_net_set; + } void updateDemand(int32_t net_idx, std::set orient_set, ChangeType change_type) { for (const Orientation& orient : orient_set) { @@ -213,7 +321,13 @@ class SRNode : public LayerCoord _net_orient_map[net_idx].insert(orient); } else { _orient_net_map[orient].erase(net_idx); + if (_orient_net_map[orient].empty()) { + _orient_net_map.erase(orient); + } _net_orient_map[net_idx].erase(orient); + if (_net_orient_map[net_idx].empty()) { + _net_orient_map.erase(net_idx); + } } } } @@ -240,6 +354,7 @@ class SRNode : public LayerCoord double _internal_via_unit = -1; std::map _neighbor_node_map; std::map _orient_supply_map; + std::map> _ignore_net_orient_map; std::map> _orient_net_map; std::map> _net_orient_map; #if 1 // astar diff --git a/src/operation/iRT/source/module/supply_analyzer/CMakeLists.txt b/src/operation/iRT/source/module/supply_analyzer/CMakeLists.txt index 00587776c3ddf737163315b74af28ca73d682c05..6e362f772e362ab2449cc9a66517caaf30edb233 100644 --- a/src/operation/iRT/source/module/supply_analyzer/CMakeLists.txt +++ b/src/operation/iRT/source/module/supply_analyzer/CMakeLists.txt @@ -2,8 +2,8 @@ if(DEBUG_IRT_SUPPLY_ANALYZER) message(STATUS "RT: DEBUG_IRT_SUPPLY_ANALYZER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_SUPPLY_ANALYZER") - set(CMAKE_BUILD_TYPE "Release") + message(STATUS "RT: RELEASE_IRT_SUPPLY_ANALYZER") + set(CMAKE_BUILD_TYPE "Release") endif() add_library(irt_supply_analyzer @@ -11,16 +11,16 @@ add_library(irt_supply_analyzer ${IRT_MODULE}/supply_analyzer/SupplyAnalyzer.cpp ) -target_link_libraries(irt_supply_analyzer +target_link_libraries(irt_supply_analyzer PUBLIC - irt_data_manager - irt_module - irt_toolkit + irt_data_manager + irt_module + irt_toolkit ) -target_include_directories(irt_supply_analyzer +target_include_directories(irt_supply_analyzer PUBLIC - ${IRT_MODULE}/supply_analyzer/sa_data_manager - ${IRT_MODULE}/supply_analyzer - + ${IRT_MODULE}/supply_analyzer/sa_data_manager + ${IRT_MODULE}/supply_analyzer + ) diff --git a/src/operation/iRT/source/module/supply_analyzer/SupplyAnalyzer.cpp b/src/operation/iRT/source/module/supply_analyzer/SupplyAnalyzer.cpp index fec8414c5bb4cd20a2fae44872f0b92d90a11ebd..51e06e8bffd05cf51ddf5bcc56ff74476df4fe21 100644 --- a/src/operation/iRT/source/module/supply_analyzer/SupplyAnalyzer.cpp +++ b/src/operation/iRT/source/module/supply_analyzer/SupplyAnalyzer.cpp @@ -58,7 +58,7 @@ void SupplyAnalyzer::analyze() setSAComParam(sa_model); buildSupplySchedule(sa_model); analyzeSupply(sa_model); - replenishPinSupply(sa_model); + buildIgnoreNet(sa_model); analyzeDemandUnit(sa_model); // debugPlotSAModel(sa_model); updateSummary(sa_model); @@ -80,10 +80,10 @@ SAModel SupplyAnalyzer::initSAModel() void SupplyAnalyzer::setSAComParam(SAModel& sa_model) { - double supply_reduction = 0.2; + int32_t supply_reduction = 0; double boundary_wire_unit = 1; double internal_wire_unit = 1; - double internal_via_unit = 0.5; + double internal_via_unit = 1; /** * supply_reduction, boundary_wire_unit, internal_wire_unit, internal_via_unit */ @@ -138,7 +138,7 @@ void SupplyAnalyzer::analyzeSupply(SAModel& sa_model) RTLOG.info(Loc::current(), "Starting..."); GridMap& gcell_map = RTDM.getDatabase().get_gcell_map(); - double supply_reduction = sa_model.get_sa_com_param().get_supply_reduction(); + int32_t supply_reduction = sa_model.get_sa_com_param().get_supply_reduction(); size_t total_pair_num = 0; for (std::vector>& grid_pair_list : sa_model.get_grid_pair_list_list()) { @@ -181,7 +181,7 @@ void SupplyAnalyzer::analyzeSupply(SAModel& sa_model) } for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(search_rect)) { for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { if (!net_shape.get_is_routing()) { continue; } @@ -202,18 +202,17 @@ void SupplyAnalyzer::analyzeSupply(SAModel& sa_model) } } std::vector wire_list = getCrossingWireList(search_rect); + int32_t max_supply = std::max(0, static_cast(wire_list.size()) - supply_reduction); + + int32_t supply = 0; for (LayerRect& wire : wire_list) { if (isAccess(wire, obs_rect_list)) { - first_orient_supply_map[first_orientation]++; - second_orient_supply_map[second_orientation]++; + supply++; } } - int32_t max_supply = std::max(0, static_cast(std::round(static_cast(wire_list.size()) * (1 - supply_reduction)))); - for (auto& [orient, supply] : first_orient_supply_map) { - supply = std::min(supply, max_supply); - } - for (auto& [orient, supply] : second_orient_supply_map) { - supply = std::min(supply, max_supply); + if (supply > 0) { + first_orient_supply_map[first_orientation] = std::min(supply, max_supply); + second_orient_supply_map[second_orientation] = std::min(supply, max_supply); } } analyzed_pair_num += grid_pair_list.size(); @@ -231,8 +230,30 @@ EXTLayerRect SupplyAnalyzer::getSearchRect(LayerCoord& first_coord, LayerCoord& if (first_coord.get_layer_idx() != second_coord.get_layer_idx()) { RTLOG.error(Loc::current(), "The grid_pair layer_idx is not equal!"); } + PlanarRect search_real_rect; + { + PlanarRect first_real_rect = RTUTIL.getRealRectByGCell(first_coord, gcell_axis); + PlanarCoord first_mid_coord = first_real_rect.getMidPoint(); + PlanarRect second_real_rect = RTUTIL.getRealRectByGCell(second_coord, gcell_axis); + PlanarCoord second_mid_coord = second_real_rect.getMidPoint(); + if (RTUTIL.isHorizontal(first_coord, second_coord)) { + std::vector coord_list; + coord_list.emplace_back(first_mid_coord.get_x(), first_real_rect.get_ll_y()); + coord_list.emplace_back(first_mid_coord.get_x(), first_real_rect.get_ur_y()); + coord_list.emplace_back(second_mid_coord.get_x(), second_real_rect.get_ll_y()); + coord_list.emplace_back(second_mid_coord.get_x(), second_real_rect.get_ur_y()); + search_real_rect = RTUTIL.getBoundingBox(coord_list); + } else if (RTUTIL.isVertical(first_coord, second_coord)) { + std::vector coord_list; + coord_list.emplace_back(first_real_rect.get_ll_x(), first_mid_coord.get_y()); + coord_list.emplace_back(first_real_rect.get_ur_x(), first_mid_coord.get_y()); + coord_list.emplace_back(second_real_rect.get_ll_x(), second_mid_coord.get_y()); + coord_list.emplace_back(second_real_rect.get_ur_x(), second_mid_coord.get_y()); + search_real_rect = RTUTIL.getBoundingBox(coord_list); + } + } EXTLayerRect search_rect; - search_rect.set_real_rect(RTUTIL.getBoundingBox({RTUTIL.getRealRectByGCell(first_coord, gcell_axis), RTUTIL.getRealRectByGCell(second_coord, gcell_axis)})); + search_rect.set_real_rect(search_real_rect); search_rect.set_grid_rect(RTUTIL.getClosedGCellGridRect(search_rect.get_real_rect(), gcell_axis)); search_rect.set_layer_idx(first_coord.get_layer_idx()); return search_rect; @@ -279,59 +300,70 @@ bool SupplyAnalyzer::isAccess(LayerRect& wire, std::vector& obs_rect return true; } -void SupplyAnalyzer::replenishPinSupply(SAModel& sa_model) +void SupplyAnalyzer::buildIgnoreNet(SAModel& sa_model) { - Die& die = RTDM.getDatabase().get_die(); - GridMap& gcell_map = RTDM.getDatabase().get_gcell_map(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); + GridMap& gcell_map = RTDM.getDatabase().get_gcell_map(); int32_t bottom_routing_layer_idx = RTDM.getConfig().bottom_routing_layer_idx; int32_t top_routing_layer_idx = RTDM.getConfig().top_routing_layer_idx; - std::map>, CmpPlanarCoordByXASC> coord_routing_net_map; - for (auto& [net_idx, access_point_set] : RTDM.getNetAccessPointMap(die)) { - for (AccessPoint* access_point : access_point_set) { - coord_routing_net_map[access_point->get_grid_coord()][access_point->get_layer_idx()].insert(net_idx); - } - } - for (auto& [grid_coord, routing_net_map] : coord_routing_net_map) { - std::map routing_min_supply_map; - { - std::set bottom_net_idx_set; - for (int32_t routing_layer_idx = 0; routing_layer_idx <= bottom_routing_layer_idx; routing_layer_idx++) { - if (RTUTIL.exist(routing_net_map, routing_layer_idx)) { - bottom_net_idx_set.insert(routing_net_map[routing_layer_idx].begin(), routing_net_map[routing_layer_idx].end()); + for (int32_t x = 0; x < gcell_map.get_x_size(); x++) { + for (int32_t y = 0; y < gcell_map.get_y_size(); y++) { + std::map>> routing_ignore_net_orient_map; + for (auto& [is_routing, layer_net_fixed_rect_map] : gcell_map[x][y].get_type_layer_net_fixed_rect_map()) { + if (!is_routing) { + continue; } - routing_min_supply_map[routing_layer_idx] = static_cast(bottom_net_idx_set.size()); - } - std::set top_net_idx_set; - for (int32_t routing_layer_idx = static_cast(routing_layer_list.size()) - 1; top_routing_layer_idx <= routing_layer_idx; routing_layer_idx--) { - if (RTUTIL.exist(routing_net_map, routing_layer_idx)) { - top_net_idx_set.insert(routing_net_map[routing_layer_idx].begin(), routing_net_map[routing_layer_idx].end()); + for (auto& [layer_idx, net_fixed_rect_map] : layer_net_fixed_rect_map) { + for (auto& [net_idx, fixed_rect_set] : net_fixed_rect_map) { + if (net_idx == -1) { + continue; + } + for (EXTLayerRect* fixed_rect : fixed_rect_set) { + if (RTUTIL.isClosedOverlap(gcell_map[x][y], fixed_rect->get_real_rect())) { + routing_ignore_net_orient_map[layer_idx][net_idx] = {}; + } + } + } } - routing_min_supply_map[routing_layer_idx] = static_cast(top_net_idx_set.size()); } - for (int32_t routing_layer_idx = bottom_routing_layer_idx + 1; routing_layer_idx < top_routing_layer_idx; routing_layer_idx++) { - if (RTUTIL.exist(routing_net_map, routing_layer_idx)) { - routing_min_supply_map[routing_layer_idx] = static_cast(routing_net_map[routing_layer_idx].size()); + for (auto& [net_idx, segment_set] : gcell_map[x][y].get_net_detailed_result_map()) { + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { + if (!net_shape.get_is_routing()) { + continue; + } + if (RTUTIL.isClosedOverlap(gcell_map[x][y], net_shape.get_rect())) { + routing_ignore_net_orient_map[net_shape.get_layer_idx()][net_idx] = {}; + } + } } } - } - GCell& gcell = gcell_map[grid_coord.get_x()][grid_coord.get_y()]; - for (auto& [routing_layer_idx, min_supply] : routing_min_supply_map) { - if (min_supply <= 0) { - continue; + for (auto& [net_idx, patch_set] : gcell_map[x][y].get_net_detailed_patch_map()) { + for (EXTLayerRect* patch : patch_set) { + if (RTUTIL.isClosedOverlap(gcell_map[x][y], patch->get_real_rect())) { + routing_ignore_net_orient_map[patch->get_layer_idx()][net_idx] = {}; + } + } } - if (routing_layer_list[routing_layer_idx].isPreferH()) { - for (Orientation orientation : {Orientation::kEast, Orientation::kWest}) { - int32_t& supply = gcell.get_routing_orient_supply_map()[routing_layer_idx][orientation]; - supply = std::max(supply, min_supply); + for (auto& [routing_layer_idx, ignore_net_orient_map] : routing_ignore_net_orient_map) { + std::set ignore_orient_set; + ignore_orient_set.insert(Orientation::kAbove); + ignore_orient_set.insert(Orientation::kBelow); + if (bottom_routing_layer_idx <= routing_layer_idx && routing_layer_idx <= top_routing_layer_idx) { + if (routing_layer_list[routing_layer_idx].isPreferH()) { + ignore_orient_set.insert(Orientation::kWest); + ignore_orient_set.insert(Orientation::kEast); + } else { + ignore_orient_set.insert(Orientation::kSouth); + ignore_orient_set.insert(Orientation::kNorth); + } } - } else { - for (Orientation orientation : {Orientation::kSouth, Orientation::kNorth}) { - int32_t& supply = gcell.get_routing_orient_supply_map()[routing_layer_idx][orientation]; - supply = std::max(supply, min_supply); + for (auto& [net_idx, orient_set] : ignore_net_orient_map) { + orient_set = ignore_orient_set; } } + gcell_map[x][y].set_routing_ignore_net_orient_map(routing_ignore_net_orient_map); } } } @@ -466,6 +498,17 @@ void SupplyAnalyzer::debugPlotSAModel(SAModel& sa_model) GPGDS gp_gds; + // base_region + { + GPStruct base_region_struct("base_region"); + GPBoundary gp_boundary; + gp_boundary.set_layer_idx(0); + gp_boundary.set_data_type(0); + gp_boundary.set_rect(die.get_real_rect()); + base_region_struct.push(gp_boundary); + gp_gds.addStruct(base_region_struct); + } + // gcell_axis { GPStruct gcell_axis_struct("gcell_axis"); @@ -537,7 +580,7 @@ void SupplyAnalyzer::debugPlotSAModel(SAModel& sa_model) for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { GPStruct detailed_result_struct(RTUTIL.getString("detailed_result(net_", net_idx, ")")); for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { GPBoundary gp_boundary; gp_boundary.set_data_type(static_cast(GPDataType::kShape)); gp_boundary.set_rect(net_shape.get_rect()); @@ -565,34 +608,81 @@ void SupplyAnalyzer::debugPlotSAModel(SAModel& sa_model) gp_gds.addStruct(detailed_patch_struct); } - // supply_map + // gcell_map { - GPStruct supply_map_struct("supply_map"); - for (int32_t x = 0; x < gcell_map.get_x_size(); x++) { - for (int32_t y = 0; y < gcell_map.get_y_size(); y++) { - PlanarRect shape = RTUTIL.getRealRectByGCell(x, y, gcell_axis); - for (auto& [layer_idx, orient_supply_map] : gcell_map[x][y].get_routing_orient_supply_map()) { - int32_t y_reduced_span = shape.getYSpan() / 25; - int32_t y = shape.get_ur_y(); + GPStruct gcell_map_struct("gcell_map"); + for (RoutingLayer& routing_layer : routing_layer_list) { + for (int32_t grid_x = 0; grid_x < gcell_map.get_x_size(); grid_x++) { + for (int32_t grid_y = 0; grid_y < gcell_map.get_y_size(); grid_y++) { + GCell& gcell = gcell_map[grid_x][grid_y]; + PlanarRect real_rect = RTUTIL.getRealRectByGCell(grid_x, grid_y, gcell_axis); + int32_t y_reduced_span = std::max(1, real_rect.getYSpan() / 12); + int32_t y = real_rect.get_ur_y(); + + y -= y_reduced_span; + GPText gp_text_node_grid_coord; + gp_text_node_grid_coord.set_coord(real_rect.get_ll_x(), y); + gp_text_node_grid_coord.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_node_grid_coord.set_message(RTUTIL.getString("(", grid_x, " , ", y, " , ", routing_layer.get_layer_idx(), ")")); + gp_text_node_grid_coord.set_layer_idx(RTGP.getGDSIdxByRouting(routing_layer.get_layer_idx())); + gp_text_node_grid_coord.set_presentation(GPTextPresentation::kLeftMiddle); + gcell_map_struct.push(gp_text_node_grid_coord); + + if (RTUTIL.exist(gcell.get_routing_orient_supply_map(), routing_layer.get_layer_idx())) { + y -= y_reduced_span; + GPText gp_text_orient_supply_map; + gp_text_orient_supply_map.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_supply_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_orient_supply_map.set_message("orient_supply_map: "); + gp_text_orient_supply_map.set_layer_idx(RTGP.getGDSIdxByRouting(routing_layer.get_layer_idx())); + gp_text_orient_supply_map.set_presentation(GPTextPresentation::kLeftMiddle); + gcell_map_struct.push(gp_text_orient_supply_map); - if (!orient_supply_map.empty()) { y -= y_reduced_span; GPText gp_text_orient_supply_map_info; - gp_text_orient_supply_map_info.set_coord(shape.get_ll_x(), y); + gp_text_orient_supply_map_info.set_coord(real_rect.get_ll_x(), y); gp_text_orient_supply_map_info.set_text_type(static_cast(GPDataType::kInfo)); - std::string orient_supply_map_message = "--"; - for (auto& [orientation, supply] : orient_supply_map) { - orient_supply_map_message += RTUTIL.getString("(", GetOrientationName()(orientation), ":", supply, ")"); + std::string orient_supply_map_info_message = "--"; + for (auto& [orient, supply] : gcell.get_routing_orient_supply_map()[routing_layer.get_layer_idx()]) { + orient_supply_map_info_message += RTUTIL.getString("(", GetOrientationName()(orient), ",", supply, ")"); } - gp_text_orient_supply_map_info.set_message(orient_supply_map_message); - gp_text_orient_supply_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(static_cast(layer_idx))); + gp_text_orient_supply_map_info.set_message(orient_supply_map_info_message); + gp_text_orient_supply_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(routing_layer.get_layer_idx())); gp_text_orient_supply_map_info.set_presentation(GPTextPresentation::kLeftMiddle); - supply_map_struct.push(gp_text_orient_supply_map_info); + gcell_map_struct.push(gp_text_orient_supply_map_info); + } + + if (RTUTIL.exist(gcell.get_routing_ignore_net_orient_map(), routing_layer.get_layer_idx())) { + y -= y_reduced_span; + GPText gp_text_ignore_net_map; + gp_text_ignore_net_map.set_coord(real_rect.get_ll_x(), y); + gp_text_ignore_net_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_ignore_net_map.set_message("ignore_net_map: "); + gp_text_ignore_net_map.set_layer_idx(RTGP.getGDSIdxByRouting(routing_layer.get_layer_idx())); + gp_text_ignore_net_map.set_presentation(GPTextPresentation::kLeftMiddle); + gcell_map_struct.push(gp_text_ignore_net_map); + + y -= y_reduced_span; + GPText gp_text_ignore_net_map_info; + gp_text_ignore_net_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_ignore_net_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string ignore_net_map_info_message = "--"; + for (auto& [net_idx, orient_set] : gcell.get_routing_ignore_net_orient_map()[routing_layer.get_layer_idx()]) { + ignore_net_map_info_message += RTUTIL.getString("(", net_idx); + for (Orientation orient : orient_set) { + ignore_net_map_info_message += RTUTIL.getString(",", GetOrientationName()(orient)); + } + ignore_net_map_info_message += RTUTIL.getString(")"); + } + gp_text_ignore_net_map_info.set_message(ignore_net_map_info_message); + gp_text_ignore_net_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(routing_layer.get_layer_idx())); + gp_text_ignore_net_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + gcell_map_struct.push(gp_text_ignore_net_map_info); } } } } - gp_gds.addStruct(supply_map_struct); + gp_gds.addStruct(gcell_map_struct); } std::string gds_file_path = RTUTIL.getString(sa_temp_directory_path, "supply.gds"); diff --git a/src/operation/iRT/source/module/supply_analyzer/SupplyAnalyzer.hpp b/src/operation/iRT/source/module/supply_analyzer/SupplyAnalyzer.hpp index b560570b96c72bdeefdd0219014cb1eab4cad198..6233a9fec41199a9e13f1cdebeb5ed9ede2d305b 100644 --- a/src/operation/iRT/source/module/supply_analyzer/SupplyAnalyzer.hpp +++ b/src/operation/iRT/source/module/supply_analyzer/SupplyAnalyzer.hpp @@ -53,7 +53,7 @@ class SupplyAnalyzer EXTLayerRect getSearchRect(LayerCoord& first_coord, LayerCoord& second_coord); std::vector getCrossingWireList(EXTLayerRect& search_rect); bool isAccess(LayerRect& wire, std::vector& obs_rect_list); - void replenishPinSupply(SAModel& sa_model); + void buildIgnoreNet(SAModel& sa_model); void analyzeDemandUnit(SAModel& sa_model); #if 1 // exhibit diff --git a/src/operation/iRT/source/module/supply_analyzer/sa_data_manager/SAComParam.hpp b/src/operation/iRT/source/module/supply_analyzer/sa_data_manager/SAComParam.hpp index 79b59d3ae7d82db57e55a6038198fd4e004353b5..6a12bc598af559f43512367e3f46b1fe15b77232 100644 --- a/src/operation/iRT/source/module/supply_analyzer/sa_data_manager/SAComParam.hpp +++ b/src/operation/iRT/source/module/supply_analyzer/sa_data_manager/SAComParam.hpp @@ -22,7 +22,7 @@ class SAComParam { public: SAComParam() = default; - SAComParam(double supply_reduction, double boundary_wire_unit, double internal_wire_unit, double internal_via_unit) + SAComParam(int32_t supply_reduction, double boundary_wire_unit, double internal_wire_unit, double internal_via_unit) { _supply_reduction = supply_reduction; _boundary_wire_unit = boundary_wire_unit; @@ -31,18 +31,18 @@ class SAComParam } ~SAComParam() = default; // getter - double get_supply_reduction() const { return _supply_reduction; } + int32_t get_supply_reduction() const { return _supply_reduction; } double get_boundary_wire_unit() const { return _boundary_wire_unit; } double get_internal_wire_unit() const { return _internal_wire_unit; } double get_internal_via_unit() const { return _internal_via_unit; } // setter - void set_supply_reduction(const double supply_reduction) { _supply_reduction = supply_reduction; } + void set_supply_reduction(const int32_t supply_reduction) { _supply_reduction = supply_reduction; } void set_boundary_wire_unit(const double boundary_wire_unit) { _boundary_wire_unit = boundary_wire_unit; } void set_internal_wire_unit(const double internal_wire_unit) { _internal_wire_unit = internal_wire_unit; } void set_internal_via_unit(const double internal_via_unit) { _internal_via_unit = internal_via_unit; } private: - double _supply_reduction = -1; + int32_t _supply_reduction = -1; double _boundary_wire_unit = -1; double _internal_wire_unit = -1; double _internal_via_unit = -1; diff --git a/src/operation/iRT/source/module/topology_generator/CMakeLists.txt b/src/operation/iRT/source/module/topology_generator/CMakeLists.txt index e9651e102116c4a93715dad55fb5ac57bf4ae4f2..d5b805967a5965ebfa17966ba13e506895dede8d 100644 --- a/src/operation/iRT/source/module/topology_generator/CMakeLists.txt +++ b/src/operation/iRT/source/module/topology_generator/CMakeLists.txt @@ -2,8 +2,8 @@ if(DEBUG_IRT_TOPOLOGY_GENERATOR) message(STATUS "RT: DEBUG_IRT_TOPOLOGY_GENERATOR") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_TOPOLOGY_GENERATOR") - set(CMAKE_BUILD_TYPE "Release") + message(STATUS "RT: RELEASE_IRT_TOPOLOGY_GENERATOR") + set(CMAKE_BUILD_TYPE "Release") endif() add_library(irt_topology_generator @@ -11,16 +11,16 @@ add_library(irt_topology_generator ${IRT_MODULE}/topology_generator/TopologyGenerator.cpp ) -target_link_libraries(irt_topology_generator +target_link_libraries(irt_topology_generator PUBLIC - irt_data_manager - irt_module - irt_toolkit + irt_data_manager + irt_module + irt_toolkit ) -target_include_directories(irt_topology_generator +target_include_directories(irt_topology_generator PUBLIC - ${IRT_MODULE}/topology_generator/tg_data_manager - ${IRT_MODULE}/topology_generator - + ${IRT_MODULE}/topology_generator/tg_data_manager + ${IRT_MODULE}/topology_generator + ) diff --git a/src/operation/iRT/source/module/topology_generator/TopologyGenerator.cpp b/src/operation/iRT/source/module/topology_generator/TopologyGenerator.cpp index d840ead475cb557900600d3c6aef2e577e47a0b5..f5ff67533a613412a9c69f24a9c43a144f5884bb 100644 --- a/src/operation/iRT/source/module/topology_generator/TopologyGenerator.cpp +++ b/src/operation/iRT/source/module/topology_generator/TopologyGenerator.cpp @@ -18,6 +18,7 @@ #include "GDSPlotter.hpp" #include "RTInterface.hpp" +#include "TGCandidate.hpp" #include "Utility.hpp" namespace irt { @@ -61,13 +62,13 @@ void TopologyGenerator::generate() buildOrientSupply(tg_model); // debugCheckTGModel(tg_model); generateTGModel(tg_model); + // debugPlotTGModel(tg_model, "after"); updateSummary(tg_model); printSummary(tg_model); outputGuide(tg_model); outputNetCSV(tg_model); outputOverflowCSV(tg_model); - outputNetJson(tg_model); - outputOverflowJson(tg_model); + outputJson(tg_model); RTLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); } @@ -110,16 +111,20 @@ TGNet TopologyGenerator::convertToTGNet(Net& net) void TopologyGenerator::setTGComParam(TGModel& tg_model) { int32_t topo_spilt_length = 10; + int32_t expand_step_num = 5; + int32_t expand_step_length = 2; double prefer_wire_unit = 1; double non_prefer_wire_unit = 2.5 * prefer_wire_unit; double overflow_unit = 4 * non_prefer_wire_unit; /** - * topo_spilt_length, overflow_unit + * topo_spilt_length, expand_step_num, expand_step_length, overflow_unit */ // clang-format off - TGComParam tg_com_param(topo_spilt_length, overflow_unit); + TGComParam tg_com_param(topo_spilt_length, expand_step_num, expand_step_length, overflow_unit); // clang-format on RTLOG.info(Loc::current(), "topo_spilt_length: ", tg_com_param.get_topo_spilt_length()); + RTLOG.info(Loc::current(), "expand_step_num: ", tg_com_param.get_expand_step_num()); + RTLOG.info(Loc::current(), "expand_step_length: ", tg_com_param.get_expand_step_length()); RTLOG.info(Loc::current(), "overflow_unit: ", tg_com_param.get_overflow_unit()); tg_model.set_tg_com_param(tg_com_param); } @@ -151,6 +156,11 @@ void TopologyGenerator::buildTGNodeMap(TGModel& tg_model) tg_node.set_boundary_wire_unit(gcell_map[x][y].get_boundary_wire_unit()); tg_node.set_internal_wire_unit(gcell_map[x][y].get_internal_wire_unit()); tg_node.set_internal_via_unit(gcell_map[x][y].get_internal_via_unit()); + for (auto& [routing_layer_idx, ignore_net_orient_map] : gcell_map[x][y].get_routing_ignore_net_orient_map()) { + for (auto& [net_idx, orient_set] : ignore_net_orient_map) { + tg_node.get_ignore_net_orient_map()[net_idx].insert(orient_set.begin(), orient_set.end()); + } + } } } RTLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); @@ -233,12 +243,7 @@ void TopologyGenerator::generateTGModel(TGModel& tg_model) void TopologyGenerator::routeTGTask(TGModel& tg_model, TGNet* tg_task) { initSingleTask(tg_model, tg_task); - std::vector> routing_segment_list; - for (Segment& planar_topo : getPlanarTopoList(tg_model)) { - for (Segment& routing_segment : getRoutingSegmentList(tg_model, planar_topo)) { - routing_segment_list.push_back(routing_segment); - } - } + std::vector> routing_segment_list = getRoutingSegmentList(tg_model); MTree coord_tree = getCoordTree(tg_model, routing_segment_list); updateDemandToGraph(tg_model, ChangeType::kAdd, coord_tree); uploadNetResult(tg_model, coord_tree); @@ -250,6 +255,39 @@ void TopologyGenerator::initSingleTask(TGModel& tg_model, TGNet* tg_task) tg_model.set_curr_tg_task(tg_task); } +std::vector> TopologyGenerator::getRoutingSegmentList(TGModel& tg_model) +{ + std::vector> planar_topo_list = getPlanarTopoList(tg_model); + + std::vector tg_candidate_list; + for (size_t i = 0; i < planar_topo_list.size(); i++) { + for (std::vector> routing_segment_list : getRoutingSegmentListList(tg_model, planar_topo_list[i])) { + tg_candidate_list.emplace_back(i, routing_segment_list, 0); + } + } +#pragma omp parallel for + for (TGCandidate& tg_candidate : tg_candidate_list) { + tg_candidate.set_cost(getNodeCost(tg_model, tg_candidate.get_routing_segment_list())); + } + std::map topo_candidate_map; + for (TGCandidate& tg_candidate : tg_candidate_list) { + int32_t topo_idx = tg_candidate.get_topo_idx(); + if (!RTUTIL.exist(topo_candidate_map, topo_idx)) { + topo_candidate_map[topo_idx] = &tg_candidate; + } + if (tg_candidate.get_cost() < topo_candidate_map[topo_idx]->get_cost()) { + topo_candidate_map[topo_idx] = &tg_candidate; + } + } + std::vector> routing_segment_list; + for (auto& [topo_idx, min_candidate] : topo_candidate_map) { + for (Segment& routing_segment : min_candidate->get_routing_segment_list()) { + routing_segment_list.push_back(routing_segment); + } + } + return routing_segment_list; +} + std::vector> TopologyGenerator::getPlanarTopoList(TGModel& tg_model) { int32_t topo_spilt_length = tg_model.get_tg_com_param().get_topo_spilt_length(); @@ -301,34 +339,39 @@ std::vector> TopologyGenerator::getPlanarTopoList(TGModel& return planar_topo_list; } -std::vector> TopologyGenerator::getRoutingSegmentList(TGModel& tg_model, Segment& planar_topo) +std::vector>> TopologyGenerator::getRoutingSegmentListList(TGModel& tg_model, Segment& planar_topo) { - std::vector> routing_segment_list; + std::vector>> routing_segment_list_list; for (auto getRoutingSegmentList : {std::bind(&TopologyGenerator::getRoutingSegmentListByStraight, this, std::placeholders::_1, std::placeholders::_2), - std::bind(&TopologyGenerator::getRoutingSegmentListByLPattern, this, std::placeholders::_1, std::placeholders::_2)}) { - if (routing_segment_list.empty()) { - routing_segment_list = getRoutingSegmentList(tg_model, planar_topo); + std::bind(&TopologyGenerator::getRoutingSegmentListByLPattern, this, std::placeholders::_1, std::placeholders::_2), + std::bind(&TopologyGenerator::getRoutingSegmentListByZPattern, this, std::placeholders::_1, std::placeholders::_2), + std::bind(&TopologyGenerator::getRoutingSegmentListByUPattern, this, std::placeholders::_1, std::placeholders::_2), + std::bind(&TopologyGenerator::getRoutingSegmentListByInner3Bends, this, std::placeholders::_1, std::placeholders::_2), + std::bind(&TopologyGenerator::getRoutingSegmentListByOuter3Bends, this, std::placeholders::_1, std::placeholders::_2)}) { + for (std::vector> routing_segment_list : getRoutingSegmentList(tg_model, planar_topo)) { + routing_segment_list_list.push_back(routing_segment_list); } } - if (routing_segment_list.empty()) { - RTLOG.error(Loc::current(), "The routing_segment_list is empty"); - } - return routing_segment_list; + return routing_segment_list_list; } -std::vector> TopologyGenerator::getRoutingSegmentListByStraight(TGModel& tg_model, Segment& planar_topo) +std::vector>> TopologyGenerator::getRoutingSegmentListByStraight(TGModel& tg_model, Segment& planar_topo) { PlanarCoord& first_coord = planar_topo.get_first(); PlanarCoord& second_coord = planar_topo.get_second(); if (RTUTIL.isOblique(first_coord, second_coord)) { return {}; } - std::vector> routing_segment_list; - routing_segment_list.emplace_back(first_coord, second_coord); - return routing_segment_list; + std::vector>> routing_segment_list_list; + { + std::vector> routing_segment_list; + routing_segment_list.emplace_back(first_coord, second_coord); + routing_segment_list_list.push_back(routing_segment_list); + } + return routing_segment_list_list; } -std::vector> TopologyGenerator::getRoutingSegmentListByLPattern(TGModel& tg_model, Segment& planar_topo) +std::vector>> TopologyGenerator::getRoutingSegmentListByLPattern(TGModel& tg_model, Segment& planar_topo) { PlanarCoord& first_coord = planar_topo.get_first(); PlanarCoord& second_coord = planar_topo.get_second(); @@ -344,28 +387,303 @@ std::vector> TopologyGenerator::getRoutingSegmentListByLPat std::vector>> routing_segment_list_list; for (std::vector& inflection_list : inflection_list_list) { std::vector> routing_segment_list; - if (inflection_list.empty()) { - routing_segment_list.emplace_back(planar_topo.get_first(), planar_topo.get_second()); - } else { - routing_segment_list.emplace_back(planar_topo.get_first(), inflection_list.front()); - for (size_t i = 1; i < inflection_list.size(); i++) { - routing_segment_list.emplace_back(inflection_list[i - 1], inflection_list[i]); + routing_segment_list.emplace_back(planar_topo.get_first(), inflection_list.front()); + for (size_t i = 1; i < inflection_list.size(); i++) { + routing_segment_list.emplace_back(inflection_list[i - 1], inflection_list[i]); + } + routing_segment_list.emplace_back(inflection_list.back(), planar_topo.get_second()); + routing_segment_list_list.push_back(routing_segment_list); + } + return routing_segment_list_list; +} + +std::vector>> TopologyGenerator::getRoutingSegmentListByZPattern(TGModel& tg_model, Segment& planar_topo) +{ + PlanarCoord& first_coord = planar_topo.get_first(); + PlanarCoord& second_coord = planar_topo.get_second(); + if (RTUTIL.isRightAngled(first_coord, second_coord)) { + return {}; + } + std::vector x_mid_index_list = getMidIndexList(first_coord.get_x(), second_coord.get_x()); + std::vector y_mid_index_list = getMidIndexList(first_coord.get_y(), second_coord.get_y()); + if (x_mid_index_list.empty() && y_mid_index_list.empty()) { + return {}; + } + std::vector> inflection_list_list; + for (size_t i = 0; i < x_mid_index_list.size(); i++) { + PlanarCoord inflection_coord1(x_mid_index_list[i], first_coord.get_y()); + PlanarCoord inflection_coord2(x_mid_index_list[i], second_coord.get_y()); + inflection_list_list.push_back({inflection_coord1, inflection_coord2}); + } + for (size_t i = 0; i < y_mid_index_list.size(); i++) { + PlanarCoord inflection_coord1(first_coord.get_x(), y_mid_index_list[i]); + PlanarCoord inflection_coord2(second_coord.get_x(), y_mid_index_list[i]); + inflection_list_list.push_back({inflection_coord1, inflection_coord2}); + } + std::vector>> routing_segment_list_list; + for (std::vector& inflection_list : inflection_list_list) { + std::vector> routing_segment_list; + routing_segment_list.emplace_back(planar_topo.get_first(), inflection_list.front()); + for (size_t i = 1; i < inflection_list.size(); i++) { + routing_segment_list.emplace_back(inflection_list[i - 1], inflection_list[i]); + } + routing_segment_list.emplace_back(inflection_list.back(), planar_topo.get_second()); + routing_segment_list_list.push_back(routing_segment_list); + } + return routing_segment_list_list; +} + +std::vector TopologyGenerator::getMidIndexList(int32_t first_idx, int32_t second_idx) +{ + std::vector mid_index_list; + RTUTIL.swapByASC(first_idx, second_idx); + mid_index_list.reserve(second_idx - first_idx - 1); + for (int32_t i = (first_idx + 1); i <= (second_idx - 1); i++) { + mid_index_list.push_back(i); + } + return mid_index_list; +} + +std::vector>> TopologyGenerator::getRoutingSegmentListByUPattern(TGModel& tg_model, Segment& planar_topo) +{ + Die& die = RTDM.getDatabase().get_die(); + int32_t expand_step_num = tg_model.get_tg_com_param().get_expand_step_num(); + int32_t expand_step_length = tg_model.get_tg_com_param().get_expand_step_length(); + + PlanarCoord& first_coord = planar_topo.get_first(); + PlanarCoord& second_coord = planar_topo.get_second(); + if (RTUTIL.getManhattanDistance(first_coord, second_coord) <= 1) { + return {}; + } + int32_t first_x = first_coord.get_x(); + int32_t second_x = second_coord.get_x(); + int32_t first_y = first_coord.get_y(); + int32_t second_y = second_coord.get_y(); + RTUTIL.swapByASC(first_x, second_x); + RTUTIL.swapByASC(first_y, second_y); + + std::vector> inflection_list_list; + if (!RTUTIL.isHorizontal(first_coord, second_coord)) { + for (int32_t i = 0; i < expand_step_num; i++) { + first_x -= expand_step_length; + if (first_x >= die.get_grid_ll_x()) { + PlanarCoord inflection_coord1(first_x, first_coord.get_y()); + PlanarCoord inflection_coord2(first_x, second_coord.get_y()); + inflection_list_list.push_back({inflection_coord1, inflection_coord2}); + } + second_x += expand_step_length; + if (second_x <= die.get_grid_ur_x()) { + PlanarCoord inflection_coord1(second_x, first_coord.get_y()); + PlanarCoord inflection_coord2(second_x, second_coord.get_y()); + inflection_list_list.push_back({inflection_coord1, inflection_coord2}); } - routing_segment_list.emplace_back(inflection_list.back(), planar_topo.get_second()); } + } + if (!RTUTIL.isVertical(first_coord, second_coord)) { + for (int32_t i = 0; i < expand_step_num; i++) { + first_y -= expand_step_length; + if (first_y >= die.get_grid_ll_y()) { + PlanarCoord inflection_coord1(first_coord.get_x(), first_y); + PlanarCoord inflection_coord2(second_coord.get_x(), first_y); + inflection_list_list.push_back({inflection_coord1, inflection_coord2}); + } + second_y += expand_step_length; + if (second_y <= die.get_grid_ur_y()) { + PlanarCoord inflection_coord1(first_coord.get_x(), second_y); + PlanarCoord inflection_coord2(second_coord.get_x(), second_y); + inflection_list_list.push_back({inflection_coord1, inflection_coord2}); + } + } + } + std::vector>> routing_segment_list_list; + for (std::vector& inflection_list : inflection_list_list) { + std::vector> routing_segment_list; + routing_segment_list.emplace_back(planar_topo.get_first(), inflection_list.front()); + for (size_t i = 1; i < inflection_list.size(); i++) { + routing_segment_list.emplace_back(inflection_list[i - 1], inflection_list[i]); + } + routing_segment_list.emplace_back(inflection_list.back(), planar_topo.get_second()); routing_segment_list_list.push_back(routing_segment_list); } + return routing_segment_list_list; +} + +std::vector>> TopologyGenerator::getRoutingSegmentListByInner3Bends(TGModel& tg_model, Segment& planar_topo) +{ + PlanarCoord& first_coord = planar_topo.get_first(); + PlanarCoord& second_coord = planar_topo.get_second(); + if (RTUTIL.isRightAngled(first_coord, second_coord)) { + return {}; + } + std::vector x_mid_index_list = getMidIndexList(first_coord.get_x(), second_coord.get_x()); + std::vector y_mid_index_list = getMidIndexList(first_coord.get_y(), second_coord.get_y()); + if (x_mid_index_list.empty() || y_mid_index_list.empty()) { + return {}; + } + std::vector> inflection_list_list; + for (size_t i = 0; i < x_mid_index_list.size(); i++) { + for (size_t j = 0; j < y_mid_index_list.size(); j++) { + PlanarCoord inflection_coord1(x_mid_index_list[i], first_coord.get_y()); + PlanarCoord inflection_coord2(x_mid_index_list[i], y_mid_index_list[j]); + PlanarCoord inflection_coord3(second_coord.get_x(), y_mid_index_list[j]); + inflection_list_list.push_back({inflection_coord1, inflection_coord2, inflection_coord3}); + } + } - double min_cost = DBL_MAX; - size_t min_i = 0; - for (size_t i = 0; i < routing_segment_list_list.size(); i++) { - double cost = getNodeCost(tg_model, routing_segment_list_list[i]); - if (cost < min_cost) { - min_cost = cost; - min_i = i; + for (size_t i = 0; i < x_mid_index_list.size(); i++) { + for (size_t j = 0; j < y_mid_index_list.size(); j++) { + PlanarCoord inflection_coord1(first_coord.get_x(), y_mid_index_list[j]); + PlanarCoord inflection_coord2(x_mid_index_list[i], y_mid_index_list[j]); + PlanarCoord inflection_coord3(x_mid_index_list[i], second_coord.get_y()); + inflection_list_list.push_back({inflection_coord1, inflection_coord2, inflection_coord3}); } } - return routing_segment_list_list[min_i]; + std::vector>> routing_segment_list_list; + for (std::vector& inflection_list : inflection_list_list) { + std::vector> routing_segment_list; + routing_segment_list.emplace_back(planar_topo.get_first(), inflection_list.front()); + for (size_t i = 1; i < inflection_list.size(); i++) { + routing_segment_list.emplace_back(inflection_list[i - 1], inflection_list[i]); + } + routing_segment_list.emplace_back(inflection_list.back(), planar_topo.get_second()); + routing_segment_list_list.push_back(routing_segment_list); + } + return routing_segment_list_list; +} + +std::vector>> TopologyGenerator::getRoutingSegmentListByOuter3Bends(TGModel& tg_model, Segment& planar_topo) +{ + Die& die = RTDM.getDatabase().get_die(); + int32_t expand_step_num = tg_model.get_tg_com_param().get_expand_step_num(); + int32_t expand_step_length = tg_model.get_tg_com_param().get_expand_step_length(); + + PlanarCoord& first_coord = planar_topo.get_first(); + PlanarCoord& second_coord = planar_topo.get_second(); + if (RTUTIL.isRightAngled(first_coord, second_coord)) { + return {}; + } + int32_t start_x = first_coord.get_x(); + int32_t end_x = second_coord.get_x(); + int32_t start_y = first_coord.get_y(); + int32_t end_y = second_coord.get_y(); + + int32_t box_lb_x = std::min(start_x, end_x); + int32_t box_rt_x = std::max(start_x, end_x); + int32_t box_lb_y = std::min(start_y, end_y); + int32_t box_rt_y = std::max(start_y, end_y); + + std::vector> inflection_list_list; + for (int32_t i = 0; i < expand_step_num; i++) { + box_lb_x -= expand_step_length; + box_rt_x += expand_step_length; + box_lb_y -= expand_step_length; + box_rt_y += expand_step_length; + if (start_x < end_x) { + if (start_y < end_y) { + /** + * line style + * + * x(e) + * x + * x + * x(s) + * + */ + if (die.get_grid_ll_y() <= box_lb_y && box_rt_x <= die.get_grid_ur_x()) { + PlanarCoord inflection_coord1(start_x, box_lb_y); + PlanarCoord inflection_coord2(box_rt_x, box_lb_y); + PlanarCoord inflection_coord3(box_rt_x, end_y); + inflection_list_list.push_back({inflection_coord1, inflection_coord2, inflection_coord3}); + } + if (die.get_grid_ll_x() <= box_lb_x && box_rt_y <= die.get_grid_ur_y()) { + PlanarCoord inflection_coord1(box_lb_x, start_y); + PlanarCoord inflection_coord2(box_lb_x, box_rt_y); + PlanarCoord inflection_coord3(end_x, box_rt_y); + inflection_list_list.push_back({inflection_coord1, inflection_coord2, inflection_coord3}); + } + } else { + /** + * line style + * + * x(s) + * x + * x + * x(e) + * + */ + if (box_rt_x <= die.get_grid_ur_x() && box_rt_y <= die.get_grid_ur_y()) { + PlanarCoord inflection_coord1(start_x, box_rt_y); + PlanarCoord inflection_coord2(box_rt_x, box_rt_y); + PlanarCoord inflection_coord3(box_rt_x, end_y); + inflection_list_list.push_back({inflection_coord1, inflection_coord2, inflection_coord3}); + } + if (die.get_grid_ll_x() <= box_lb_x && die.get_grid_ll_y() <= box_lb_y) { + PlanarCoord inflection_coord1(box_lb_x, start_y); + PlanarCoord inflection_coord2(box_lb_x, box_lb_y); + PlanarCoord inflection_coord3(end_x, box_lb_y); + inflection_list_list.push_back({inflection_coord1, inflection_coord2, inflection_coord3}); + } + } + + } else { + if (start_y < end_y) { + /** + * line style + * + * x(e) + * x + * x + * x(s) + * + */ + if (box_rt_x <= die.get_grid_ur_x() && box_rt_y <= die.get_grid_ur_y()) { + PlanarCoord inflection_coord1(box_rt_x, start_y); + PlanarCoord inflection_coord2(box_rt_x, box_rt_y); + PlanarCoord inflection_coord3(end_x, box_rt_y); + inflection_list_list.push_back({inflection_coord1, inflection_coord2, inflection_coord3}); + } + if (die.get_grid_ll_x() <= box_lb_x && die.get_grid_ll_y() <= box_lb_y) { + PlanarCoord inflection_coord1(start_x, box_lb_y); + PlanarCoord inflection_coord2(box_lb_x, box_lb_y); + PlanarCoord inflection_coord3(box_lb_x, end_y); + inflection_list_list.push_back({inflection_coord1, inflection_coord2, inflection_coord3}); + } + } else { + /** + * line style + * + * x(s) + * x + * x + * x(e) + * + */ + if (die.get_grid_ll_y() <= box_lb_y && box_rt_x <= die.get_grid_ur_x()) { + PlanarCoord inflection_coord1(box_rt_x, start_y); + PlanarCoord inflection_coord2(box_rt_x, box_lb_y); + PlanarCoord inflection_coord3(end_x, box_lb_y); + inflection_list_list.push_back({inflection_coord1, inflection_coord2, inflection_coord3}); + } + if (die.get_grid_ll_x() <= box_lb_x && box_rt_y <= die.get_grid_ur_y()) { + PlanarCoord inflection_coord1(start_x, box_rt_y); + PlanarCoord inflection_coord2(box_lb_x, box_rt_y); + PlanarCoord inflection_coord3(box_lb_x, end_y); + inflection_list_list.push_back({inflection_coord1, inflection_coord2, inflection_coord3}); + } + } + } + } + std::vector>> routing_segment_list_list; + for (std::vector& inflection_list : inflection_list_list) { + std::vector> routing_segment_list; + routing_segment_list.emplace_back(planar_topo.get_first(), inflection_list.front()); + for (size_t i = 1; i < inflection_list.size(); i++) { + routing_segment_list.emplace_back(inflection_list[i - 1], inflection_list[i]); + } + routing_segment_list.emplace_back(inflection_list.back(), planar_topo.get_second()); + routing_segment_list_list.push_back(routing_segment_list); + } + return routing_segment_list_list; } double TopologyGenerator::getNodeCost(TGModel& tg_model, std::vector>& routing_segment_list) @@ -378,33 +696,19 @@ double TopologyGenerator::getNodeCost(TGModel& tg_model, std::vector& coord_segment : routing_segment_list) { PlanarCoord& first_coord = coord_segment.get_first(); PlanarCoord& second_coord = coord_segment.get_second(); - - Orientation orientation = RTUTIL.getOrientation(first_coord, second_coord); - if (orientation == Orientation::kNone || orientation == Orientation::kOblique) { - RTLOG.error(Loc::current(), "The orientation is error!"); + if (!RTUTIL.isRightAngled(first_coord, second_coord)) { + RTLOG.error(Loc::current(), "The direction is error!"); } - Orientation opposite_orientation = RTUTIL.getOppositeOrientation(orientation); - - node_cost += tg_node_map[first_coord.get_x()][first_coord.get_y()].getOverflowCost(curr_net_idx, orientation, overflow_unit); - node_cost += tg_node_map[second_coord.get_x()][second_coord.get_y()].getOverflowCost(curr_net_idx, opposite_orientation, overflow_unit); - - if (RTUTIL.isHorizontal(first_coord, second_coord)) { - int32_t first_x = first_coord.get_x(); - int32_t second_x = second_coord.get_x(); - int32_t y = first_coord.get_y(); - RTUTIL.swapByASC(first_x, second_x); - for (int32_t x = (first_x + 1); x <= (second_x - 1); x++) { - node_cost += tg_node_map[x][y].getOverflowCost(curr_net_idx, orientation, overflow_unit); - node_cost += tg_node_map[x][y].getOverflowCost(curr_net_idx, opposite_orientation, overflow_unit); - } - } else if (RTUTIL.isVertical(first_coord, second_coord)) { - int32_t x = first_coord.get_x(); - int32_t first_y = first_coord.get_y(); - int32_t second_y = second_coord.get_y(); - RTUTIL.swapByASC(first_y, second_y); - for (int32_t y = (first_y + 1); y <= (second_y - 1); y++) { - node_cost += tg_node_map[x][y].getOverflowCost(curr_net_idx, orientation, overflow_unit); - node_cost += tg_node_map[x][y].getOverflowCost(curr_net_idx, opposite_orientation, overflow_unit); + int32_t first_x = first_coord.get_x(); + int32_t second_x = second_coord.get_x(); + int32_t first_y = first_coord.get_y(); + int32_t second_y = second_coord.get_y(); + RTUTIL.swapByASC(first_x, second_x); + RTUTIL.swapByASC(first_y, second_y); + Direction direction = RTUTIL.getDirection(first_coord, second_coord); + for (int32_t x = first_x; x <= second_x; x++) { + for (int32_t y = first_y; y <= second_y; y++) { + node_cost += tg_node_map[x][y].getOverflowCost(curr_net_idx, direction, overflow_unit); } } } @@ -500,8 +804,8 @@ void TopologyGenerator::updateSummary(TGModel& tg_model) double& total_demand = summary.tg_summary.total_demand; double& total_overflow = summary.tg_summary.total_overflow; double& total_wire_length = summary.tg_summary.total_wire_length; - std::map>& clock_timing = summary.tg_summary.clock_timing; - std::map& power_map = summary.tg_summary.power_map; + std::map>& clock_timing_map = summary.tg_summary.clock_timing_map; + std::map& type_power_map = summary.tg_summary.type_power_map; std::vector& tg_net_list = tg_model.get_tg_net_list(); GridMap& tg_node_map = tg_model.get_tg_node_map(); @@ -509,8 +813,8 @@ void TopologyGenerator::updateSummary(TGModel& tg_model) total_demand = 0; total_overflow = 0; total_wire_length = 0; - clock_timing.clear(); - power_map.clear(); + clock_timing_map.clear(); + type_power_map.clear(); for (int32_t x = 0; x < tg_node_map.get_x_size(); x++) { for (int32_t y = 0; y < tg_node_map.get_y_size(); y++) { @@ -558,7 +862,7 @@ void TopologyGenerator::updateSummary(TGModel& tg_model) routing_segment_list_list[net_idx].emplace_back(first_real_coord, second_real_coord); } } - RTI.updateTimingAndPower(real_pin_coord_map_list, routing_segment_list_list, clock_timing, power_map); + RTI.updateTimingAndPower(real_pin_coord_map_list, routing_segment_list_list, clock_timing_map, type_power_map); } } @@ -570,8 +874,8 @@ void TopologyGenerator::printSummary(TGModel& tg_model) double& total_demand = summary.tg_summary.total_demand; double& total_overflow = summary.tg_summary.total_overflow; double& total_wire_length = summary.tg_summary.total_wire_length; - std::map>& clock_timing = summary.tg_summary.clock_timing; - std::map& power_map = summary.tg_summary.power_map; + std::map>& clock_timing_map = summary.tg_summary.clock_timing_map; + std::map& type_power_map = summary.tg_summary.type_power_map; fort::char_table summary_table; { @@ -589,16 +893,16 @@ void TopologyGenerator::printSummary(TGModel& tg_model) << "tns" << "wns" << "freq" << fort::endr; - for (auto& [clock_name, timing_map] : clock_timing) { + for (auto& [clock_name, timing_map] : clock_timing_map) { timing_table << clock_name << timing_map["TNS"] << timing_map["WNS"] << timing_map["Freq(MHz)"] << fort::endr; } power_table << fort::header << "power_type"; - for (auto& [type, power] : power_map) { + for (auto& [type, power] : type_power_map) { power_table << fort::header << type; } power_table << fort::endr; power_table << "power_value"; - for (auto& [type, power] : power_map) { + for (auto& [type, power] : type_power_map) { power_table << power; } power_table << fort::endr; @@ -718,54 +1022,64 @@ void TopologyGenerator::outputOverflowCSV(TGModel& tg_model) RTUTIL.closeFileStream(overflow_csv_file); } -void TopologyGenerator::outputNetJson(TGModel& tg_model) +void TopologyGenerator::outputJson(TGModel& tg_model) +{ + int32_t enable_notification = RTDM.getConfig().enable_notification; + if (!enable_notification) { + return; + } + std::map json_path_map; + json_path_map["net_map"] = outputNetJson(tg_model); + json_path_map["overflow_map"] = outputOverflowJson(tg_model); + json_path_map["summary"] = outputSummaryJson(tg_model); + RTI.sendNotification("TG", 1, json_path_map); +} + +std::string TopologyGenerator::outputNetJson(TGModel& tg_model) { Die& die = RTDM.getDatabase().get_die(); ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& net_list = RTDM.getDatabase().get_net_list(); std::string& tg_temp_directory_path = RTDM.getConfig().tg_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector net_json_list; - net_json_list.resize(net_list.size()); - for (Net& net : net_list) { - net_json_list[net.get_net_idx()]["net_name"] = net.get_net_name(); - } - for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { - for (Segment* segment : segment_set) { - PlanarRect first_gcell = RTUTIL.getRealRectByGCell(segment->get_first(), gcell_axis); - PlanarRect second_gcell = RTUTIL.getRealRectByGCell(segment->get_second(), gcell_axis); - if (segment->get_first().get_layer_idx() != segment->get_second().get_layer_idx()) { - net_json_list[net_idx]["result"].push_back({first_gcell.get_ll_x(), first_gcell.get_ll_y(), first_gcell.get_ur_x(), first_gcell.get_ur_y(), - routing_layer_list[segment->get_first().get_layer_idx()].get_layer_name()}); - net_json_list[net_idx]["result"].push_back({second_gcell.get_ll_x(), second_gcell.get_ll_y(), second_gcell.get_ur_x(), second_gcell.get_ur_y(), - routing_layer_list[segment->get_second().get_layer_idx()].get_layer_name()}); - } else { - PlanarRect gcell = RTUTIL.getBoundingBox({first_gcell, second_gcell}); - net_json_list[net_idx]["result"].push_back({gcell.get_ll_x(), gcell.get_ll_y(), gcell.get_ur_x(), gcell.get_ur_y(), - routing_layer_list[segment->get_first().get_layer_idx()].get_layer_name()}); + { + nlohmann::json result_shape_json; + for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { + std::string net_name = net_list[net_idx].get_net_name(); + for (Segment* segment : segment_set) { + PlanarRect first_gcell = RTUTIL.getRealRectByGCell(segment->get_first(), gcell_axis); + PlanarRect second_gcell = RTUTIL.getRealRectByGCell(segment->get_second(), gcell_axis); + if (segment->get_first().get_layer_idx() != segment->get_second().get_layer_idx()) { + result_shape_json["result_shape"][net_name]["path"].push_back({first_gcell.get_ll_x(), first_gcell.get_ll_y(), first_gcell.get_ur_x(), + first_gcell.get_ur_y(), + routing_layer_list[segment->get_first().get_layer_idx()].get_layer_name()}); + result_shape_json["result_shape"][net_name]["path"].push_back({second_gcell.get_ll_x(), second_gcell.get_ll_y(), second_gcell.get_ur_x(), + second_gcell.get_ur_y(), + routing_layer_list[segment->get_second().get_layer_idx()].get_layer_name()}); + } else { + PlanarRect gcell = RTUTIL.getBoundingBox({first_gcell, second_gcell}); + result_shape_json["result_shape"][net_name]["path"].push_back({gcell.get_ll_x(), gcell.get_ll_y(), gcell.get_ur_x(), gcell.get_ur_y(), + routing_layer_list[segment->get_first().get_layer_idx()].get_layer_name()}); + } } } + net_json_list.push_back(result_shape_json); } std::string net_json_file_path = RTUTIL.getString(tg_temp_directory_path, "net_map.json"); std::ofstream* net_json_file = RTUTIL.getOutputFileStream(net_json_file_path); (*net_json_file) << net_json_list; RTUTIL.closeFileStream(net_json_file); - RTI.sendNotification(RTUTIL.getString("TG_net_map"), net_json_file_path); + return net_json_file_path; } -void TopologyGenerator::outputOverflowJson(TGModel& tg_model) +std::string TopologyGenerator::outputOverflowJson(TGModel& tg_model) { ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::string& tg_temp_directory_path = RTDM.getConfig().tg_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + GridMap& tg_node_map = tg_model.get_tg_node_map(); std::vector overflow_json_list; for (int32_t x = 0; x < tg_node_map.get_x_size(); x++) { @@ -779,13 +1093,350 @@ void TopologyGenerator::outputOverflowJson(TGModel& tg_model) std::ofstream* overflow_json_file = RTUTIL.getOutputFileStream(overflow_json_file_path); (*overflow_json_file) << overflow_json_list; RTUTIL.closeFileStream(overflow_json_file); - RTI.sendNotification(RTUTIL.getString("TG_overflow_map"), overflow_json_file_path); + return overflow_json_file_path; +} + +std::string TopologyGenerator::outputSummaryJson(TGModel& tg_model) +{ + Summary& summary = RTDM.getDatabase().get_summary(); + std::string& tg_temp_directory_path = RTDM.getConfig().tg_temp_directory_path; + + double& total_demand = summary.tg_summary.total_demand; + double& total_overflow = summary.tg_summary.total_overflow; + double& total_wire_length = summary.tg_summary.total_wire_length; + std::map>& clock_timing_map = summary.tg_summary.clock_timing_map; + std::map& type_power_map = summary.tg_summary.type_power_map; + + nlohmann::json summary_json; + summary_json["total_demand"] = total_demand; + summary_json["total_overflow"] = total_overflow; + summary_json["total_wire_length"] = total_wire_length; + for (auto& [clock_name, timing] : clock_timing_map) { + summary_json["clock_timing_map"]["clock_name"] = clock_name; + summary_json["clock_timing_map"]["timing"] = timing; + } + for (auto& [type, power] : type_power_map) { + summary_json["type_power_map"]["type"] = type; + summary_json["type_power_map"]["power"] = power; + } + std::string summary_json_file_path = RTUTIL.getString(tg_temp_directory_path, "summary.json"); + std::ofstream* summary_json_file = RTUTIL.getOutputFileStream(summary_json_file_path); + (*summary_json_file) << summary_json; + RTUTIL.closeFileStream(summary_json_file); + return summary_json_file_path; } #endif #if 1 // debug +void TopologyGenerator::debugPlotTGModel(TGModel& tg_model, std::string flag) +{ + ScaleAxis& gcell_axis = RTDM.getDatabase().get_gcell_axis(); + Die& die = RTDM.getDatabase().get_die(); + std::string& tg_temp_directory_path = RTDM.getConfig().tg_temp_directory_path; + + int32_t point_size = 5; + + GPGDS gp_gds; + + // base_region + { + GPStruct base_region_struct("base_region"); + GPBoundary gp_boundary; + gp_boundary.set_layer_idx(0); + gp_boundary.set_data_type(0); + gp_boundary.set_rect(die.get_real_rect()); + base_region_struct.push(gp_boundary); + gp_gds.addStruct(base_region_struct); + } + + // gcell_axis + { + GPStruct gcell_axis_struct("gcell_axis"); + std::vector gcell_x_list = RTUTIL.getScaleList(die.get_real_ll_x(), die.get_real_ur_x(), gcell_axis.get_x_grid_list()); + std::vector gcell_y_list = RTUTIL.getScaleList(die.get_real_ll_y(), die.get_real_ur_y(), gcell_axis.get_y_grid_list()); + for (int32_t x : gcell_x_list) { + GPPath gp_path; + gp_path.set_layer_idx(0); + gp_path.set_data_type(1); + gp_path.set_segment(x, die.get_real_ll_y(), x, die.get_real_ur_y()); + gcell_axis_struct.push(gp_path); + } + for (int32_t y : gcell_y_list) { + GPPath gp_path; + gp_path.set_layer_idx(0); + gp_path.set_data_type(1); + gp_path.set_segment(die.get_real_ll_x(), y, die.get_real_ur_x(), y); + gcell_axis_struct.push(gp_path); + } + gp_gds.addStruct(gcell_axis_struct); + } + + // fixed_rect + for (auto& [is_routing, layer_net_rect_map] : RTDM.getTypeLayerNetFixedRectMap(die)) { + for (auto& [layer_idx, net_rect_map] : layer_net_rect_map) { + for (auto& [net_idx, rect_set] : net_rect_map) { + GPStruct fixed_rect_struct(RTUTIL.getString("fixed_rect(net_", net_idx, ")")); + for (EXTLayerRect* rect : rect_set) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kShape)); + gp_boundary.set_rect(rect->get_real_rect()); + if (is_routing) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(layer_idx)); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(layer_idx)); + } + fixed_rect_struct.push(gp_boundary); + } + gp_gds.addStruct(fixed_rect_struct); + } + } + } + + // access_point + for (auto& [net_idx, access_point_set] : RTDM.getNetAccessPointMap(die)) { + GPStruct access_point_struct(RTUTIL.getString("access_point(net_", net_idx, ")")); + for (AccessPoint* access_point : access_point_set) { + int32_t x = access_point->get_real_x(); + int32_t y = access_point->get_real_y(); + + GPBoundary access_point_boundary; + access_point_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(access_point->get_layer_idx())); + access_point_boundary.set_data_type(static_cast(GPDataType::kAccessPoint)); + access_point_boundary.set_rect(x - point_size, y - point_size, x + point_size, y + point_size); + access_point_struct.push(access_point_boundary); + } + gp_gds.addStruct(access_point_struct); + } + + // routing result + for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { + GPStruct global_result_struct(RTUTIL.getString("global_result(net_", net_idx, ")")); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetGlobalShapeList(net_idx, *segment)) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kGlobalPath)); + gp_boundary.set_rect(net_shape.get_rect()); + if (net_shape.get_is_routing()) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(net_shape.get_layer_idx())); + } + global_result_struct.push(gp_boundary); + } + } + gp_gds.addStruct(global_result_struct); + } + + // routing result + for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { + GPStruct detailed_result_struct(RTUTIL.getString("detailed_result(net_", net_idx, ")")); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kShape)); + gp_boundary.set_rect(net_shape.get_rect()); + if (net_shape.get_is_routing()) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(net_shape.get_layer_idx())); + } + detailed_result_struct.push(gp_boundary); + } + } + gp_gds.addStruct(detailed_result_struct); + } + + // routing patch + for (auto& [net_idx, patch_set] : RTDM.getNetDetailedPatchMap(die)) { + GPStruct detailed_patch_struct(RTUTIL.getString("detailed_patch(net_", net_idx, ")")); + for (EXTLayerRect* patch : patch_set) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kShape)); + gp_boundary.set_rect(patch->get_real_rect()); + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(patch->get_layer_idx())); + detailed_patch_struct.push(gp_boundary); + } + gp_gds.addStruct(detailed_patch_struct); + } + + { + GridMap& tg_node_map = tg_model.get_tg_node_map(); + // tg_node_map + { + GPStruct tg_node_map_struct("tg_node_map"); + for (int32_t grid_x = 0; grid_x < tg_node_map.get_x_size(); grid_x++) { + for (int32_t grid_y = 0; grid_y < tg_node_map.get_y_size(); grid_y++) { + TGNode& tg_node = tg_node_map[grid_x][grid_y]; + PlanarRect real_rect = RTUTIL.getRealRectByGCell(tg_node, gcell_axis); + int32_t y_reduced_span = std::max(1, real_rect.getYSpan() / 12); + int32_t y = real_rect.get_ur_y(); + + y -= y_reduced_span; + GPText gp_text_node_real_coord; + gp_text_node_real_coord.set_coord(real_rect.get_ll_x(), y); + gp_text_node_real_coord.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_node_real_coord.set_message(RTUTIL.getString("(", tg_node.get_x(), " , ", tg_node.get_y(), " , ", 0, ")")); + gp_text_node_real_coord.set_layer_idx(RTGP.getGDSIdxByRouting(0)); + gp_text_node_real_coord.set_presentation(GPTextPresentation::kLeftMiddle); + tg_node_map_struct.push(gp_text_node_real_coord); + + y -= y_reduced_span; + GPText gp_text_node_grid_coord; + gp_text_node_grid_coord.set_coord(real_rect.get_ll_x(), y); + gp_text_node_grid_coord.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_node_grid_coord.set_message(RTUTIL.getString("(", grid_x, " , ", grid_y, " , ", 0, ")")); + gp_text_node_grid_coord.set_layer_idx(RTGP.getGDSIdxByRouting(0)); + gp_text_node_grid_coord.set_presentation(GPTextPresentation::kLeftMiddle); + tg_node_map_struct.push(gp_text_node_grid_coord); + + y -= y_reduced_span; + GPText gp_text_orient_supply_map; + gp_text_orient_supply_map.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_supply_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_orient_supply_map.set_message("orient_supply_map: "); + gp_text_orient_supply_map.set_layer_idx(RTGP.getGDSIdxByRouting(0)); + gp_text_orient_supply_map.set_presentation(GPTextPresentation::kLeftMiddle); + tg_node_map_struct.push(gp_text_orient_supply_map); + + if (!tg_node.get_orient_supply_map().empty()) { + y -= y_reduced_span; + GPText gp_text_orient_supply_map_info; + gp_text_orient_supply_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_supply_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string orient_supply_map_info_message = "--"; + for (auto& [orient, supply] : tg_node.get_orient_supply_map()) { + orient_supply_map_info_message += RTUTIL.getString("(", GetOrientationName()(orient), ",", supply, ")"); + } + gp_text_orient_supply_map_info.set_message(orient_supply_map_info_message); + gp_text_orient_supply_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(0)); + gp_text_orient_supply_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + tg_node_map_struct.push(gp_text_orient_supply_map_info); + } + + y -= y_reduced_span; + GPText gp_text_ignore_net_orient_map; + gp_text_ignore_net_orient_map.set_coord(real_rect.get_ll_x(), y); + gp_text_ignore_net_orient_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_ignore_net_orient_map.set_message("ignore_net_orient_map: "); + gp_text_ignore_net_orient_map.set_layer_idx(RTGP.getGDSIdxByRouting(0)); + gp_text_ignore_net_orient_map.set_presentation(GPTextPresentation::kLeftMiddle); + tg_node_map_struct.push(gp_text_ignore_net_orient_map); + + if (!tg_node.get_ignore_net_orient_map().empty()) { + y -= y_reduced_span; + GPText gp_text_ignore_net_orient_map_info; + gp_text_ignore_net_orient_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_ignore_net_orient_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string ignore_net_orient_map_info_message = "--"; + for (auto& [net_idx, orient_set] : tg_node.get_ignore_net_orient_map()) { + ignore_net_orient_map_info_message += RTUTIL.getString("(", net_idx); + for (Orientation orient : orient_set) { + ignore_net_orient_map_info_message += RTUTIL.getString(",", GetOrientationName()(orient)); + } + ignore_net_orient_map_info_message += RTUTIL.getString(")"); + } + gp_text_ignore_net_orient_map_info.set_message(ignore_net_orient_map_info_message); + gp_text_ignore_net_orient_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(0)); + gp_text_ignore_net_orient_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + tg_node_map_struct.push(gp_text_ignore_net_orient_map_info); + } + + y -= y_reduced_span; + GPText gp_text_orient_net_map; + gp_text_orient_net_map.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_net_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_orient_net_map.set_message("orient_net_map: "); + gp_text_orient_net_map.set_layer_idx(RTGP.getGDSIdxByRouting(0)); + gp_text_orient_net_map.set_presentation(GPTextPresentation::kLeftMiddle); + tg_node_map_struct.push(gp_text_orient_net_map); + + if (!tg_node.get_orient_net_map().empty()) { + y -= y_reduced_span; + GPText gp_text_orient_net_map_info; + gp_text_orient_net_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_orient_net_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string orient_net_map_info_message = "--"; + for (auto& [orient, net_set] : tg_node.get_orient_net_map()) { + orient_net_map_info_message += RTUTIL.getString("(", GetOrientationName()(orient)); + for (int32_t net_idx : net_set) { + orient_net_map_info_message += RTUTIL.getString(",", net_idx); + } + orient_net_map_info_message += RTUTIL.getString(")"); + } + gp_text_orient_net_map_info.set_message(orient_net_map_info_message); + gp_text_orient_net_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(0)); + gp_text_orient_net_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + tg_node_map_struct.push(gp_text_orient_net_map_info); + } + + y -= y_reduced_span; + GPText gp_text_net_orient_map; + gp_text_net_orient_map.set_coord(real_rect.get_ll_x(), y); + gp_text_net_orient_map.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_net_orient_map.set_message("net_orient_map: "); + gp_text_net_orient_map.set_layer_idx(RTGP.getGDSIdxByRouting(0)); + gp_text_net_orient_map.set_presentation(GPTextPresentation::kLeftMiddle); + tg_node_map_struct.push(gp_text_net_orient_map); + + if (!tg_node.get_net_orient_map().empty()) { + y -= y_reduced_span; + GPText gp_text_net_orient_map_info; + gp_text_net_orient_map_info.set_coord(real_rect.get_ll_x(), y); + gp_text_net_orient_map_info.set_text_type(static_cast(GPDataType::kInfo)); + std::string net_orient_map_info_message = "--"; + for (auto& [net_idx, orient_set] : tg_node.get_net_orient_map()) { + net_orient_map_info_message += RTUTIL.getString("(", net_idx); + for (Orientation orient : orient_set) { + net_orient_map_info_message += RTUTIL.getString(",", GetOrientationName()(orient)); + } + net_orient_map_info_message += RTUTIL.getString(")"); + } + gp_text_net_orient_map_info.set_message(net_orient_map_info_message); + gp_text_net_orient_map_info.set_layer_idx(RTGP.getGDSIdxByRouting(0)); + gp_text_net_orient_map_info.set_presentation(GPTextPresentation::kLeftMiddle); + tg_node_map_struct.push(gp_text_net_orient_map_info); + } + + y -= y_reduced_span; + GPText gp_text_overflow; + gp_text_overflow.set_coord(real_rect.get_ll_x(), y); + gp_text_overflow.set_text_type(static_cast(GPDataType::kInfo)); + gp_text_overflow.set_message(RTUTIL.getString("overflow: ", tg_node.getOverflow())); + gp_text_overflow.set_layer_idx(RTGP.getGDSIdxByRouting(0)); + gp_text_overflow.set_presentation(GPTextPresentation::kLeftMiddle); + tg_node_map_struct.push(gp_text_overflow); + } + } + gp_gds.addStruct(tg_node_map_struct); + } + // overflow + { + GPStruct overflow_struct("overflow"); + for (int32_t grid_x = 0; grid_x < tg_node_map.get_x_size(); grid_x++) { + for (int32_t grid_y = 0; grid_y < tg_node_map.get_y_size(); grid_y++) { + TGNode& tg_node = tg_node_map[grid_x][grid_y]; + if (tg_node.getOverflow() <= 0) { + continue; + } + PlanarRect real_rect = RTUTIL.getRealRectByGCell(tg_node, gcell_axis); + + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kOverflow)); + gp_boundary.set_rect(real_rect); + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(0)); + overflow_struct.push(gp_boundary); + } + } + gp_gds.addStruct(overflow_struct); + } + } + + std::string gds_file_path = RTUTIL.getString(tg_temp_directory_path, flag, "_tg_model.gds"); + RTGP.plot(gp_gds, gds_file_path); +} + void TopologyGenerator::debugCheckTGModel(TGModel& tg_model) { GridMap& tg_node_map = tg_model.get_tg_node_map(); diff --git a/src/operation/iRT/source/module/topology_generator/TopologyGenerator.hpp b/src/operation/iRT/source/module/topology_generator/TopologyGenerator.hpp index 9fe9526054ec21f86e06b6e27becbde57208bab7..241961faf3469b2951f10750b794ff41c8c46769 100644 --- a/src/operation/iRT/source/module/topology_generator/TopologyGenerator.hpp +++ b/src/operation/iRT/source/module/topology_generator/TopologyGenerator.hpp @@ -57,10 +57,16 @@ class TopologyGenerator void generateTGModel(TGModel& tg_model); void routeTGTask(TGModel& tg_model, TGNet* tg_net); void initSingleTask(TGModel& tg_model, TGNet* tg_net); + std::vector> getRoutingSegmentList(TGModel& tg_model); std::vector> getPlanarTopoList(TGModel& tg_model); - std::vector> getRoutingSegmentList(TGModel& tg_model, Segment& planar_topo); - std::vector> getRoutingSegmentListByStraight(TGModel& tg_model, Segment& planar_topo); - std::vector> getRoutingSegmentListByLPattern(TGModel& tg_model, Segment& planar_topo); + std::vector>> getRoutingSegmentListList(TGModel& tg_model, Segment& planar_topo); + std::vector>> getRoutingSegmentListByStraight(TGModel& tg_model, Segment& planar_topo); + std::vector>> getRoutingSegmentListByLPattern(TGModel& tg_model, Segment& planar_topo); + std::vector>> getRoutingSegmentListByZPattern(TGModel& tg_model, Segment& planar_topo); + std::vector getMidIndexList(int32_t first_idx, int32_t second_idx); + std::vector>> getRoutingSegmentListByUPattern(TGModel& tg_model, Segment& planar_topo); + std::vector>> getRoutingSegmentListByInner3Bends(TGModel& tg_model, Segment& planar_topo); + std::vector>> getRoutingSegmentListByOuter3Bends(TGModel& tg_model, Segment& planar_topo); double getNodeCost(TGModel& tg_model, std::vector>& routing_segment_list); MTree getCoordTree(TGModel& tg_model, std::vector>& routing_segment_list); void uploadNetResult(TGModel& tg_model, MTree& coord_tree); @@ -76,11 +82,14 @@ class TopologyGenerator void outputGuide(TGModel& tg_model); void outputNetCSV(TGModel& tg_model); void outputOverflowCSV(TGModel& tg_model); - void outputNetJson(TGModel& tg_model); - void outputOverflowJson(TGModel& tg_model); + void outputJson(TGModel& tg_model); + std::string outputNetJson(TGModel& tg_model); + std::string outputOverflowJson(TGModel& tg_model); + std::string outputSummaryJson(TGModel& tg_model); #endif #if 1 // debug + void debugPlotTGModel(TGModel& tg_model, std::string flag); void debugCheckTGModel(TGModel& tg_model); #endif }; diff --git a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LATopo.hpp b/src/operation/iRT/source/module/topology_generator/tg_data_manager/TGCandidate.hpp similarity index 47% rename from src/operation/iRT/source/module/layer_assigner/la_data_manager/LATopo.hpp rename to src/operation/iRT/source/module/topology_generator/tg_data_manager/TGCandidate.hpp index d76f55775c0479ca5feb996e7534cf9d5a102ea1..0462f7f00ecf4b41aaa7107795016be6603664e0 100644 --- a/src/operation/iRT/source/module/layer_assigner/la_data_manager/LATopo.hpp +++ b/src/operation/iRT/source/module/topology_generator/tg_data_manager/TGCandidate.hpp @@ -16,35 +16,37 @@ // *************************************************************************************** #pragma once -#include "LAGroup.hpp" +#include "PlanarCoord.hpp" +#include "RTHeader.hpp" +#include "Segment.hpp" namespace irt { -class LATopo +class TGCandidate { public: - LATopo() = default; - ~LATopo() = default; + TGCandidate() = default; + TGCandidate(int32_t topo_idx, const std::vector>& routing_segment_list, double cost) + { + _topo_idx = topo_idx; + _routing_segment_list = routing_segment_list; + _cost = cost; + } + ~TGCandidate() = default; // getter - int32_t get_net_idx() { return _net_idx; } - std::vector& get_la_group_list() { return _la_group_list; } - PlanarRect& get_bounding_box() { return _bounding_box; } - std::vector>& get_routing_segment_list() { return _routing_segment_list; } - // const getter - const std::vector& get_la_group_list() const { return _la_group_list; } - const PlanarRect& get_bounding_box() const { return _bounding_box; } + int32_t get_topo_idx() const { return _topo_idx; } + std::vector>& get_routing_segment_list() { return _routing_segment_list; } + double get_cost() const { return _cost; } // setter - void set_net_idx(const int32_t net_idx) { _net_idx = net_idx; } - void set_la_group_list(const std::vector& la_group_list) { _la_group_list = la_group_list; } - void set_bounding_box(const PlanarRect& bounding_box) { _bounding_box = bounding_box; } - void set_routing_segment_list(const std::vector>& routing_segment_list) { _routing_segment_list = routing_segment_list; } + void set_topo_idx(const int32_t topo_idx) { _topo_idx = topo_idx; } + void set_routing_segment_list(const std::vector>& routing_segment_list) { _routing_segment_list = routing_segment_list; } + void set_cost(const double cost) { _cost = cost; } // function private: - int32_t _net_idx = -1; - std::vector _la_group_list; - PlanarRect _bounding_box; - std::vector> _routing_segment_list; + int32_t _topo_idx = -1; + std::vector> _routing_segment_list; + double _cost = 0.0; }; } // namespace irt diff --git a/src/operation/iRT/source/module/topology_generator/tg_data_manager/TGComParam.hpp b/src/operation/iRT/source/module/topology_generator/tg_data_manager/TGComParam.hpp index 43b6332d17fa3fa5aa5ddbdce3c6554248c9103e..0f2620360b3f97bf30c007668944c3a0a5a13a80 100644 --- a/src/operation/iRT/source/module/topology_generator/tg_data_manager/TGComParam.hpp +++ b/src/operation/iRT/source/module/topology_generator/tg_data_manager/TGComParam.hpp @@ -22,21 +22,29 @@ class TGComParam { public: TGComParam() = default; - TGComParam(int32_t topo_spilt_length, double overflow_unit) + TGComParam(int32_t topo_spilt_length, int32_t expand_step_num, int32_t expand_step_length, double overflow_unit) { _topo_spilt_length = topo_spilt_length; + _expand_step_num = expand_step_num; + _expand_step_length = expand_step_length; _overflow_unit = overflow_unit; } ~TGComParam() = default; // getter int32_t get_topo_spilt_length() const { return _topo_spilt_length; } + int32_t get_expand_step_num() const { return _expand_step_num; } + int32_t get_expand_step_length() const { return _expand_step_length; } double get_overflow_unit() const { return _overflow_unit; } // setter void set_topo_spilt_length(const int32_t topo_spilt_length) { _topo_spilt_length = topo_spilt_length; } + void set_expand_step_num(const int32_t expand_step_num) { _expand_step_num = expand_step_num; } + void set_expand_step_length(const int32_t expand_step_length) { _expand_step_length = expand_step_length; } void set_overflow_unit(const double overflow_unit) { _overflow_unit = overflow_unit; } private: int32_t _topo_spilt_length = 0; + int32_t _expand_step_num = 0; + int32_t _expand_step_length = 0; double _overflow_unit = 0; }; diff --git a/src/operation/iRT/source/module/topology_generator/tg_data_manager/TGNode.hpp b/src/operation/iRT/source/module/topology_generator/tg_data_manager/TGNode.hpp index 98e2dfa20ff5e1e51a9f0b3d684efcce1c9491e9..fee544c878e06d71fc128acc98ad6edfe071e1e5 100644 --- a/src/operation/iRT/source/module/topology_generator/tg_data_manager/TGNode.hpp +++ b/src/operation/iRT/source/module/topology_generator/tg_data_manager/TGNode.hpp @@ -35,6 +35,7 @@ class TGNode : public PlanarCoord double get_internal_via_unit() const { return _internal_via_unit; } std::map& get_neighbor_node_map() { return _neighbor_node_map; } std::map& get_orient_supply_map() { return _orient_supply_map; } + std::map>& get_ignore_net_orient_map() { return _ignore_net_orient_map; } std::map>& get_orient_net_map() { return _orient_net_map; } std::map>& get_net_orient_map() { return _net_orient_map; } // setter @@ -43,6 +44,7 @@ class TGNode : public PlanarCoord void set_internal_via_unit(const double internal_via_unit) { _internal_via_unit = internal_via_unit; } void set_neighbor_node_map(const std::map& neighbor_node_map) { _neighbor_node_map = neighbor_node_map; } void set_orient_supply_map(const std::map& orient_supply_map) { _orient_supply_map = orient_supply_map; } + void set_ignore_net_orient_map(const std::map>& ignore_net_orient_map) { _ignore_net_orient_map = ignore_net_orient_map; } void set_orient_net_map(const std::map>& orient_net_map) { _orient_net_map = orient_net_map; } void set_net_orient_map(const std::map>& net_orient_map) { _net_orient_map = net_orient_map; } // function @@ -54,56 +56,61 @@ class TGNode : public PlanarCoord } return neighbor_node; } - double getOverflowCost(int32_t curr_net_idx, Orientation orientation, double overflow_unit) + double getOverflowCost(int32_t net_idx, Direction direction, double overflow_unit) { if (!validDemandUnit()) { RTLOG.error(Loc::current(), "The demand unit is error!"); } + std::map> orient_net_map = _orient_net_map; + std::map> net_orient_map = _net_orient_map; + if (direction == Direction::kHorizontal) { + for (Orientation orient : {Orientation::kEast, Orientation::kWest}) { + orient_net_map[orient].insert(net_idx); + net_orient_map[net_idx].insert(orient); + } + } else if (direction == Direction::kVertical) { + for (Orientation orient : {Orientation::kSouth, Orientation::kNorth}) { + orient_net_map[orient].insert(net_idx); + net_orient_map[net_idx].insert(orient); + } + } else { + RTLOG.error(Loc::current(), "The direction is error!"); + } double boundary_overflow = 0; - if (orientation == Orientation::kEast || orientation == Orientation::kWest || orientation == Orientation::kSouth || orientation == Orientation::kNorth) { + for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { double boundary_demand = 0; - if (RTUTIL.exist(_orient_net_map, orientation)) { - std::set& net_set = _orient_net_map[orientation]; - boundary_demand += (static_cast(net_set.size()) * _boundary_wire_unit); - if (RTUTIL.exist(net_set, curr_net_idx)) { - boundary_demand -= _boundary_wire_unit; + if (RTUTIL.exist(orient_net_map, orient)) { + for (int32_t demand_net_idx : orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + boundary_demand += _boundary_wire_unit; } } double boundary_supply = 0; - if (RTUTIL.exist(_orient_supply_map, orientation)) { - boundary_supply = (_orient_supply_map[orientation] * _boundary_wire_unit); + if (RTUTIL.exist(_orient_supply_map, orient)) { + boundary_supply = (_orient_supply_map[orient] * _boundary_wire_unit); } - boundary_overflow = calcCost(boundary_demand + _boundary_wire_unit, boundary_supply); + boundary_overflow += calcCost(boundary_demand, boundary_supply); } double internal_overflow = 0; { double internal_demand = 0; - for (auto& [orient, net_set] : _orient_net_map) { - if (orient == Orientation::kAbove || orient == Orientation::kBelow) { - continue; - } - internal_demand += (static_cast(net_set.size()) * _internal_wire_unit); - if (RTUTIL.exist(net_set, curr_net_idx)) { - internal_demand -= _internal_wire_unit; - } - } - for (auto& [net_idx, orient_set] : _net_orient_map) { - if (net_idx == curr_net_idx) { - continue; - } - if (RTUTIL.exist(orient_set, Orientation::kAbove) || RTUTIL.exist(orient_set, Orientation::kBelow)) { - internal_demand += _internal_via_unit; + for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { + if (RTUTIL.exist(orient_net_map, orient)) { + for (int32_t demand_net_idx : orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + internal_demand += _internal_wire_unit; + } } } double internal_supply = 0; for (auto& [orient, supply] : _orient_supply_map) { internal_supply += (supply * _internal_wire_unit); } - if (orientation == Orientation::kEast || orientation == Orientation::kWest || orientation == Orientation::kSouth || orientation == Orientation::kNorth) { - internal_overflow = calcCost(internal_demand + _internal_wire_unit, internal_supply); - } else if (orientation == Orientation::kAbove || orientation == Orientation::kBelow) { - internal_overflow = calcCost(internal_demand + _internal_via_unit, internal_supply); - } + internal_overflow += calcCost(internal_demand, internal_supply); } double cost = 0; cost += (overflow_unit * (boundary_overflow + internal_overflow)); @@ -117,9 +124,6 @@ class TGNode : public PlanarCoord if (_internal_wire_unit <= 0) { return false; } - if (_internal_via_unit <= 0) { - return false; - } return true; } double calcCost(double demand, double supply) @@ -128,9 +132,9 @@ class TGNode : public PlanarCoord if (demand == supply) { cost = 1; } else if (demand > supply) { - cost = std::pow(demand - supply + 1, 2); + cost = std::pow(demand - supply + 1, 4); } else if (demand < supply) { - cost = std::pow(demand / supply, 2); + cost = std::pow(demand / supply, 4); } return cost; } @@ -151,11 +155,6 @@ class TGNode : public PlanarCoord internal_demand += (static_cast(_orient_net_map[orient].size()) * _internal_wire_unit); } } - for (auto& [net_idx, orient_set] : _net_orient_map) { - if (RTUTIL.exist(orient_set, Orientation::kAbove) || RTUTIL.exist(orient_set, Orientation::kBelow)) { - internal_demand += _internal_via_unit; - } - } return (boundary_demand + internal_demand); } double getOverflow() @@ -167,7 +166,12 @@ class TGNode : public PlanarCoord for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { double boundary_demand = 0; if (RTUTIL.exist(_orient_net_map, orient)) { - boundary_demand = (static_cast(_orient_net_map[orient].size()) * _boundary_wire_unit); + for (int32_t demand_net_idx : _orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + boundary_demand += _boundary_wire_unit; + } } double boundary_supply = 0; if (RTUTIL.exist(_orient_supply_map, orient)) { @@ -180,12 +184,12 @@ class TGNode : public PlanarCoord double internal_demand = 0; for (Orientation orient : {Orientation::kEast, Orientation::kWest, Orientation::kSouth, Orientation::kNorth}) { if (RTUTIL.exist(_orient_net_map, orient)) { - internal_demand += (static_cast(_orient_net_map[orient].size()) * _internal_wire_unit); - } - } - for (auto& [net_idx, orient_set] : _net_orient_map) { - if (RTUTIL.exist(orient_set, Orientation::kAbove) || RTUTIL.exist(orient_set, Orientation::kBelow)) { - internal_demand += _internal_via_unit; + for (int32_t demand_net_idx : _orient_net_map[orient]) { + if (RTUTIL.exist(_ignore_net_orient_map, demand_net_idx) && RTUTIL.exist(_ignore_net_orient_map[demand_net_idx], orient)) { + continue; + } + internal_demand += _internal_wire_unit; + } } } double internal_supply = 0; @@ -204,7 +208,13 @@ class TGNode : public PlanarCoord _net_orient_map[net_idx].insert(orient); } else { _orient_net_map[orient].erase(net_idx); + if (_orient_net_map[orient].empty()) { + _orient_net_map.erase(orient); + } _net_orient_map[net_idx].erase(orient); + if (_net_orient_map[net_idx].empty()) { + _net_orient_map.erase(net_idx); + } } } } @@ -215,6 +225,7 @@ class TGNode : public PlanarCoord double _internal_via_unit = -1; std::map _neighbor_node_map; std::map _orient_supply_map; + std::map> _ignore_net_orient_map; std::map> _orient_net_map; std::map> _net_orient_map; }; diff --git a/src/operation/iRT/source/module/track_assigner/CMakeLists.txt b/src/operation/iRT/source/module/track_assigner/CMakeLists.txt index 3454936cb41e6fd054bf0e56e633f57fc36b0904..3eb8bb0a06353cbc2aeee6b3363469bd8c045f68 100644 --- a/src/operation/iRT/source/module/track_assigner/CMakeLists.txt +++ b/src/operation/iRT/source/module/track_assigner/CMakeLists.txt @@ -2,8 +2,8 @@ if(DEBUG_IRT_TRACK_ASSIGNER) message(STATUS "RT: DEBUG_IRT_TRACK_ASSIGNER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_TRACK_ASSIGNER") - set(CMAKE_BUILD_TYPE "Release") + message(STATUS "RT: RELEASE_IRT_TRACK_ASSIGNER") + set(CMAKE_BUILD_TYPE "Release") endif() add_library(irt_track_assigner @@ -11,15 +11,15 @@ add_library(irt_track_assigner ${IRT_MODULE}/track_assigner/TrackAssigner.cpp ) -target_link_libraries(irt_track_assigner +target_link_libraries(irt_track_assigner PUBLIC - irt_data_manager - irt_module - irt_toolkit + irt_data_manager + irt_module + irt_toolkit ) -target_include_directories(irt_track_assigner +target_include_directories(irt_track_assigner PUBLIC - ${IRT_MODULE}/track_assigner/ta_data_manager - ${IRT_MODULE}/track_assigner + ${IRT_MODULE}/track_assigner/ta_data_manager + ${IRT_MODULE}/track_assigner ) diff --git a/src/operation/iRT/source/module/track_assigner/TrackAssigner.cpp b/src/operation/iRT/source/module/track_assigner/TrackAssigner.cpp index a497aff6870d7b9cc86578cee53268be989ffbdb..9364dd5f996175d1181b9d3f4ca7e533bd6041a7 100644 --- a/src/operation/iRT/source/module/track_assigner/TrackAssigner.cpp +++ b/src/operation/iRT/source/module/track_assigner/TrackAssigner.cpp @@ -67,8 +67,7 @@ void TrackAssigner::assign() printSummary(ta_model); outputNetCSV(ta_model); outputViolationCSV(ta_model); - outputNetJson(ta_model); - outputViolationJson(ta_model); + outputJson(ta_model); RTLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); } @@ -263,7 +262,7 @@ void TrackAssigner::buildNetResult(TAPanel& ta_panel) { for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(ta_panel.get_panel_rect())) { for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { if (net_shape.get_is_routing() != true || net_shape.get_layer_idx() != ta_panel.get_panel_rect().get_layer_idx()) { continue; } @@ -946,6 +945,9 @@ void TrackAssigner::updateViolationList(TAPanel& ta_panel) std::vector TrackAssigner::getViolationList(TAPanel& ta_panel) { + if (RTDM.getConfig().enable_fast_mode) { + return {}; + } std::map> env_net_rect_map; std::map> result_net_rect_map; { @@ -975,7 +977,7 @@ std::vector TrackAssigner::getViolationList(TAPanel& ta_panel) for (auto& [net_idx, task_detailed_result_map] : ta_panel.get_net_task_detailed_result_map()) { for (auto& [task_idx, segment_list] : task_detailed_result_map) { for (Segment& segment : segment_list) { - for (NetShape net_shape : RTDM.getNetShapeList(net_idx, segment)) { + for (NetShape net_shape : RTDM.getNetDetailedShapeList(net_idx, segment)) { result_net_rect_map[net_idx].push_back(net_shape.get_rect()); } } @@ -1179,7 +1181,7 @@ void TrackAssigner::updateFixedRectToGraph(TAPanel& ta_panel, ChangeType change_ void TrackAssigner::updateRoutedRectToGraph(TAPanel& ta_panel, ChangeType change_type, int32_t net_idx, Segment& segment) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, segment)) { if (!net_shape.get_is_routing() || (ta_panel.get_ta_panel_id().get_layer_idx() != net_shape.get_layer_idx())) { continue; } @@ -1518,58 +1520,68 @@ void TrackAssigner::outputViolationCSV(TAModel& ta_model) } } -void TrackAssigner::outputNetJson(TAModel& ta_model) +void TrackAssigner::outputJson(TAModel& ta_model) +{ + int32_t enable_notification = RTDM.getConfig().enable_notification; + if (!enable_notification) { + return; + } + std::map json_path_map; + json_path_map["net_map"] = outputNetJson(ta_model); + json_path_map["violation_map"] = outputViolationJson(ta_model); + json_path_map["summary"] = outputSummaryJson(ta_model); + RTI.sendNotification("TA", 1, json_path_map); +} + +std::string TrackAssigner::outputNetJson(TAModel& ta_model) { Die& die = RTDM.getDatabase().get_die(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); std::vector& net_list = RTDM.getDatabase().get_net_list(); std::string& ta_temp_directory_path = RTDM.getConfig().ta_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector net_json_list; - net_json_list.resize(net_list.size()); - for (Net& net : net_list) { - net_json_list[net.get_net_idx()]["net_name"] = net.get_net_name(); - } - for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { - for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { - std::string layer_name; - if (net_shape.get_is_routing()) { - layer_name = routing_layer_list[net_shape.get_layer_idx()].get_layer_name(); - } else { - layer_name = cut_layer_list[net_shape.get_layer_idx()].get_layer_name(); + { + nlohmann::json result_shape_json; + for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { + std::string net_name = net_list[net_idx].get_net_name(); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { + std::string layer_name; + if (net_shape.get_is_routing()) { + layer_name = routing_layer_list[net_shape.get_layer_idx()].get_layer_name(); + } else { + layer_name = cut_layer_list[net_shape.get_layer_idx()].get_layer_name(); + } + result_shape_json["result_shape"][net_name]["path"].push_back( + {net_shape.get_ll_x(), net_shape.get_ll_y(), net_shape.get_ur_x(), net_shape.get_ur_y(), layer_name}); } - net_json_list[net_idx]["result"].push_back({net_shape.get_ll_x(), net_shape.get_ll_y(), net_shape.get_ur_x(), net_shape.get_ur_y(), layer_name}); } } - } - for (auto& [net_idx, patch_set] : RTDM.getNetDetailedPatchMap(die)) { - for (EXTLayerRect* patch : patch_set) { - net_json_list[net_idx]["patch"].push_back({patch->get_real_ll_x(), patch->get_real_ll_y(), patch->get_real_ur_x(), patch->get_real_ur_y(), - routing_layer_list[patch->get_layer_idx()].get_layer_name()}); + for (auto& [net_idx, patch_set] : RTDM.getNetDetailedPatchMap(die)) { + std::string net_name = net_list[net_idx].get_net_name(); + for (EXTLayerRect* patch : patch_set) { + result_shape_json["result_shape"][net_name]["patch"].push_back({patch->get_real_ll_x(), patch->get_real_ll_y(), patch->get_real_ur_x(), + patch->get_real_ur_y(), routing_layer_list[patch->get_layer_idx()].get_layer_name()}); + } } + net_json_list.push_back(result_shape_json); } std::string net_json_file_path = RTUTIL.getString(RTUTIL.getString(ta_temp_directory_path, "net_map.json")); std::ofstream* net_json_file = RTUTIL.getOutputFileStream(net_json_file_path); (*net_json_file) << net_json_list; RTUTIL.closeFileStream(net_json_file); - RTI.sendNotification(RTUTIL.getString("TA_net_map"), net_json_file_path); + return net_json_file_path; } -void TrackAssigner::outputViolationJson(TAModel& ta_model) +std::string TrackAssigner::outputViolationJson(TAModel& ta_model) { Die& die = RTDM.getDatabase().get_die(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& net_list = RTDM.getDatabase().get_net_list(); std::string& ta_temp_directory_path = RTDM.getConfig().ta_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector violation_json_list; for (Violation* violation : RTDM.getViolationSet(die)) { EXTLayerRect& violation_shape = violation->get_violation_shape(); @@ -1580,7 +1592,11 @@ void TrackAssigner::outputViolationJson(TAModel& ta_model) = {violation_shape.get_real_rect().get_ll_x(), violation_shape.get_real_rect().get_ll_y(), violation_shape.get_real_rect().get_ur_x(), violation_shape.get_real_rect().get_ur_y(), routing_layer_list[violation_shape.get_layer_idx()].get_layer_name()}; for (int32_t net_idx : violation->get_violation_net_set()) { - violation_json["net"].push_back(net_list[net_idx].get_net_name()); + if (net_idx != -1) { + violation_json["net"].push_back(net_list[net_idx].get_net_name()); + } else { + violation_json["net"].push_back("obs"); + } } violation_json_list.push_back(violation_json); } @@ -1588,7 +1604,35 @@ void TrackAssigner::outputViolationJson(TAModel& ta_model) std::ofstream* violation_json_file = RTUTIL.getOutputFileStream(violation_json_file_path); (*violation_json_file) << violation_json_list; RTUTIL.closeFileStream(violation_json_file); - RTI.sendNotification(RTUTIL.getString("TA_violation_map"), violation_json_file_path); + return violation_json_file_path; +} + +std::string TrackAssigner::outputSummaryJson(TAModel& ta_model) +{ + std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); + Summary& summary = RTDM.getDatabase().get_summary(); + std::string& ta_temp_directory_path = RTDM.getConfig().ta_temp_directory_path; + + std::map& routing_wire_length_map = summary.ta_summary.routing_wire_length_map; + double& total_wire_length = summary.ta_summary.total_wire_length; + std::map& routing_violation_num_map = summary.ta_summary.routing_violation_num_map; + int32_t& total_violation_num = summary.ta_summary.total_violation_num; + + nlohmann::json summary_json; + for (auto& [routing_layer_idx, wire_length] : routing_wire_length_map) { + summary_json["routing_wire_length_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = wire_length; + } + summary_json["total_wire_length"] = total_wire_length; + for (auto& [routing_layer_idx, violation_num] : routing_violation_num_map) { + summary_json["routing_violation_num_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = violation_num; + } + summary_json["total_violation_num"] = total_violation_num; + + std::string summary_json_file_path = RTUTIL.getString(ta_temp_directory_path, "summary.json"); + std::ofstream* summary_json_file = RTUTIL.getOutputFileStream(summary_json_file_path); + (*summary_json_file) << summary_json; + RTUTIL.closeFileStream(summary_json_file); + return summary_json_file_path; } #endif @@ -1606,6 +1650,17 @@ void TrackAssigner::debugPlotTAModel(TAModel& ta_model, std::string flag) GPGDS gp_gds; + // base_region + { + GPStruct base_region_struct("base_region"); + GPBoundary gp_boundary; + gp_boundary.set_layer_idx(0); + gp_boundary.set_data_type(0); + gp_boundary.set_rect(die.get_real_rect()); + base_region_struct.push(gp_boundary); + gp_gds.addStruct(base_region_struct); + } + // gcell_axis { GPStruct gcell_axis_struct("gcell_axis"); @@ -1689,13 +1744,32 @@ void TrackAssigner::debugPlotTAModel(TAModel& ta_model, std::string flag) gp_gds.addStruct(access_point_struct); } + // routing result + for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { + GPStruct global_result_struct(RTUTIL.getString("global_result(net_", net_idx, ")")); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetGlobalShapeList(net_idx, *segment)) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kGlobalPath)); + gp_boundary.set_rect(net_shape.get_rect()); + if (net_shape.get_is_routing()) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(net_shape.get_layer_idx())); + } + global_result_struct.push(gp_boundary); + } + } + gp_gds.addStruct(global_result_struct); + } + // routing result for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { GPStruct detailed_result_struct(RTUTIL.getString("detailed_result(net_", net_idx, ")")); for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { GPBoundary gp_boundary; - gp_boundary.set_data_type(static_cast(GPDataType::kPath)); + gp_boundary.set_data_type(static_cast(GPDataType::kDetailedPath)); gp_boundary.set_rect(net_shape.get_rect()); if (net_shape.get_is_routing()) { gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); @@ -2120,9 +2194,9 @@ void TrackAssigner::debugPlotTAPanel(TAPanel& ta_panel, std::string flag) task_struct.push(gp_boundary); } for (Segment& segment : ta_panel.get_net_task_detailed_result_map()[ta_task->get_net_idx()][ta_task->get_task_idx()]) { - for (NetShape& net_shape : RTDM.getNetShapeList(ta_task->get_net_idx(), segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(ta_task->get_net_idx(), segment)) { GPBoundary gp_boundary; - gp_boundary.set_data_type(static_cast(GPDataType::kPath)); + gp_boundary.set_data_type(static_cast(GPDataType::kDetailedPath)); gp_boundary.set_rect(net_shape.get_rect()); if (net_shape.get_is_routing()) { gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); diff --git a/src/operation/iRT/source/module/track_assigner/TrackAssigner.hpp b/src/operation/iRT/source/module/track_assigner/TrackAssigner.hpp index 0a5c24de4ba948b35ac0b9c81ed4bf4298f1efdb..d61a7a1a8c5c6483277c6866745222076b6f109c 100644 --- a/src/operation/iRT/source/module/track_assigner/TrackAssigner.hpp +++ b/src/operation/iRT/source/module/track_assigner/TrackAssigner.hpp @@ -119,8 +119,10 @@ class TrackAssigner void printSummary(TAModel& ta_model); void outputNetCSV(TAModel& ta_model); void outputViolationCSV(TAModel& ta_model); - void outputNetJson(TAModel& ta_model); - void outputViolationJson(TAModel& ta_model); + void outputJson(TAModel& ta_model); + std::string outputNetJson(TAModel& ta_model); + std::string outputViolationJson(TAModel& ta_model); + std::string outputSummaryJson(TAModel& ta_model); #endif #if 1 // debug diff --git a/src/operation/iRT/source/module/violation_reporter/CMakeLists.txt b/src/operation/iRT/source/module/violation_reporter/CMakeLists.txt index 7f929f2b0ab4d9b7930efaf547a1a472a6b79ad7..f86b7b60d449a88f0749e1b0837ff45f524fd133 100644 --- a/src/operation/iRT/source/module/violation_reporter/CMakeLists.txt +++ b/src/operation/iRT/source/module/violation_reporter/CMakeLists.txt @@ -2,8 +2,8 @@ if(DEBUG_IRT_VIOLATION_REPORTER) message(STATUS "RT: DEBUG_IRT_VIOLATION_REPORTER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_VIOLATION_REPORTER") - set(CMAKE_BUILD_TYPE "Release") + message(STATUS "RT: RELEASE_IRT_VIOLATION_REPORTER") + set(CMAKE_BUILD_TYPE "Release") endif() add_library(irt_violation_reporter @@ -11,15 +11,15 @@ add_library(irt_violation_reporter ${IRT_MODULE}/violation_reporter/ViolationReporter.cpp ) -target_link_libraries(irt_violation_reporter +target_link_libraries(irt_violation_reporter PUBLIC - irt_data_manager - irt_module - irt_toolkit + irt_data_manager + irt_module + irt_toolkit ) -target_include_directories(irt_violation_reporter +target_include_directories(irt_violation_reporter PUBLIC - ${IRT_MODULE}/violation_reporter/vr_data_manager - ${IRT_MODULE}/violation_reporter + ${IRT_MODULE}/violation_reporter/vr_data_manager + ${IRT_MODULE}/violation_reporter ) diff --git a/src/operation/iRT/source/module/violation_reporter/ViolationReporter.cpp b/src/operation/iRT/source/module/violation_reporter/ViolationReporter.cpp index 3243796aea31357e6f24c243db69c9827289cedc..4ced1eea57099d3cb4960cf69c97e9e6dd9800b7 100644 --- a/src/operation/iRT/source/module/violation_reporter/ViolationReporter.cpp +++ b/src/operation/iRT/source/module/violation_reporter/ViolationReporter.cpp @@ -61,8 +61,7 @@ void ViolationReporter::report() printSummary(vr_model); outputNetCSV(vr_model); outputViolationCSV(vr_model); - outputNetJson(vr_model); - outputViolationJson(vr_model); + outputJson(vr_model); RTLOG.info(Loc::current(), "Completed", monitor.getStatsInfo()); } @@ -195,8 +194,8 @@ void ViolationReporter::updateSummary(VRModel& vr_model) std::map& among_net_violation_type_num_map = summary.vr_summary.among_net_violation_type_num_map; std::map& among_net_routing_violation_num_map = summary.vr_summary.among_net_routing_violation_num_map; int32_t& among_net_total_violation_num = summary.vr_summary.among_net_total_violation_num; - std::map>& clock_timing = summary.vr_summary.clock_timing; - std::map& power_map = summary.vr_summary.power_map; + std::map>& clock_timing_map = summary.vr_summary.clock_timing_map; + std::map& type_power_map = summary.vr_summary.type_power_map; std::vector& vr_net_list = vr_model.get_vr_net_list(); @@ -214,8 +213,8 @@ void ViolationReporter::updateSummary(VRModel& vr_model) among_net_violation_type_num_map.clear(); among_net_routing_violation_num_map.clear(); among_net_total_violation_num = 0; - clock_timing.clear(); - power_map.clear(); + clock_timing_map.clear(); + type_power_map.clear(); for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { for (Segment* segment : segment_set) { @@ -276,7 +275,7 @@ void ViolationReporter::updateSummary(VRModel& vr_model) routing_segment_list_list[net_idx].emplace_back(segment->get_first(), segment->get_second()); } } - RTI.updateTimingAndPower(real_pin_coord_map_list, routing_segment_list_list, clock_timing, power_map); + RTI.updateTimingAndPower(real_pin_coord_map_list, routing_segment_list_list, clock_timing_map, type_power_map); } } @@ -301,8 +300,8 @@ void ViolationReporter::printSummary(VRModel& vr_model) std::map& among_net_violation_type_num_map = summary.vr_summary.among_net_violation_type_num_map; std::map& among_net_routing_violation_num_map = summary.vr_summary.among_net_routing_violation_num_map; int32_t& among_net_total_violation_num = summary.vr_summary.among_net_total_violation_num; - std::map>& clock_timing = summary.vr_summary.clock_timing; - std::map& power_map = summary.vr_summary.power_map; + std::map>& clock_timing_map = summary.vr_summary.clock_timing_map; + std::map& type_power_map = summary.vr_summary.type_power_map; fort::char_table routing_wire_length_map_table; { @@ -401,16 +400,16 @@ void ViolationReporter::printSummary(VRModel& vr_model) << "tns" << "wns" << "freq" << fort::endr; - for (auto& [clock_name, timing_map] : clock_timing) { + for (auto& [clock_name, timing_map] : clock_timing_map) { timing_table << clock_name << timing_map["TNS"] << timing_map["WNS"] << timing_map["Freq(MHz)"] << fort::endr; } power_table << fort::header << "power_type"; - for (auto& [type, power] : power_map) { + for (auto& [type, power] : type_power_map) { power_table << fort::header << type; } power_table << fort::endr; power_table << "power_value"; - for (auto& [type, power] : power_map) { + for (auto& [type, power] : type_power_map) { power_table << power; } power_table << fort::endr; @@ -508,58 +507,68 @@ void ViolationReporter::outputViolationCSV(VRModel& vr_model) } } -void ViolationReporter::outputNetJson(VRModel& vr_model) +void ViolationReporter::outputJson(VRModel& vr_model) +{ + int32_t enable_notification = RTDM.getConfig().enable_notification; + if (!enable_notification) { + return; + } + std::map json_path_map; + json_path_map["net_map"] = outputNetJson(vr_model); + json_path_map["violation_map"] = outputViolationJson(vr_model); + json_path_map["summary"] = outputSummaryJson(vr_model); + RTI.sendNotification("VR", 1, json_path_map); +} + +std::string ViolationReporter::outputNetJson(VRModel& vr_model) { Die& die = RTDM.getDatabase().get_die(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); std::vector& net_list = RTDM.getDatabase().get_net_list(); std::string& vr_temp_directory_path = RTDM.getConfig().vr_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector net_json_list; - net_json_list.resize(net_list.size()); - for (Net& net : net_list) { - net_json_list[net.get_net_idx()]["net_name"] = net.get_net_name(); - } - for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { - for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { - std::string layer_name; - if (net_shape.get_is_routing()) { - layer_name = routing_layer_list[net_shape.get_layer_idx()].get_layer_name(); - } else { - layer_name = cut_layer_list[net_shape.get_layer_idx()].get_layer_name(); + { + nlohmann::json result_shape_json; + for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { + std::string net_name = net_list[net_idx].get_net_name(); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { + std::string layer_name; + if (net_shape.get_is_routing()) { + layer_name = routing_layer_list[net_shape.get_layer_idx()].get_layer_name(); + } else { + layer_name = cut_layer_list[net_shape.get_layer_idx()].get_layer_name(); + } + result_shape_json["result_shape"][net_name]["path"].push_back( + {net_shape.get_ll_x(), net_shape.get_ll_y(), net_shape.get_ur_x(), net_shape.get_ur_y(), layer_name}); } - net_json_list[net_idx]["result"].push_back({net_shape.get_ll_x(), net_shape.get_ll_y(), net_shape.get_ur_x(), net_shape.get_ur_y(), layer_name}); } } - } - for (auto& [net_idx, patch_set] : RTDM.getNetDetailedPatchMap(die)) { - for (EXTLayerRect* patch : patch_set) { - net_json_list[net_idx]["patch"].push_back({patch->get_real_ll_x(), patch->get_real_ll_y(), patch->get_real_ur_x(), patch->get_real_ur_y(), - routing_layer_list[patch->get_layer_idx()].get_layer_name()}); + for (auto& [net_idx, patch_set] : RTDM.getNetDetailedPatchMap(die)) { + std::string net_name = net_list[net_idx].get_net_name(); + for (EXTLayerRect* patch : patch_set) { + result_shape_json["result_shape"][net_name]["patch"].push_back({patch->get_real_ll_x(), patch->get_real_ll_y(), patch->get_real_ur_x(), + patch->get_real_ur_y(), routing_layer_list[patch->get_layer_idx()].get_layer_name()}); + } } + net_json_list.push_back(result_shape_json); } std::string net_json_file_path = RTUTIL.getString(RTUTIL.getString(vr_temp_directory_path, "net_map.json")); std::ofstream* net_json_file = RTUTIL.getOutputFileStream(net_json_file_path); (*net_json_file) << net_json_list; RTUTIL.closeFileStream(net_json_file); - RTI.sendNotification(RTUTIL.getString("VR_net_map"), net_json_file_path); + return net_json_file_path; } -void ViolationReporter::outputViolationJson(VRModel& vr_model) +std::string ViolationReporter::outputViolationJson(VRModel& vr_model) { Die& die = RTDM.getDatabase().get_die(); std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); std::vector& net_list = RTDM.getDatabase().get_net_list(); std::string& vr_temp_directory_path = RTDM.getConfig().vr_temp_directory_path; - int32_t output_inter_result = RTDM.getConfig().output_inter_result; - if (!output_inter_result) { - return; - } + std::vector violation_json_list; for (Violation* violation : RTDM.getViolationSet(die)) { EXTLayerRect& violation_shape = violation->get_violation_shape(); @@ -570,7 +579,11 @@ void ViolationReporter::outputViolationJson(VRModel& vr_model) = {violation_shape.get_real_rect().get_ll_x(), violation_shape.get_real_rect().get_ll_y(), violation_shape.get_real_rect().get_ur_x(), violation_shape.get_real_rect().get_ur_y(), routing_layer_list[violation_shape.get_layer_idx()].get_layer_name()}; for (int32_t net_idx : violation->get_violation_net_set()) { - violation_json["net"].push_back(net_list[net_idx].get_net_name()); + if (net_idx != -1) { + violation_json["net"].push_back(net_list[net_idx].get_net_name()); + } else { + violation_json["net"].push_back("obs"); + } } violation_json_list.push_back(violation_json); } @@ -578,7 +591,64 @@ void ViolationReporter::outputViolationJson(VRModel& vr_model) std::ofstream* violation_json_file = RTUTIL.getOutputFileStream(violation_json_file_path); (*violation_json_file) << violation_json_list; RTUTIL.closeFileStream(violation_json_file); - RTI.sendNotification(RTUTIL.getString("VR_violation_map"), violation_json_file_path); + return violation_json_file_path; +} + +std::string ViolationReporter::outputSummaryJson(VRModel& vr_model) +{ + std::vector& routing_layer_list = RTDM.getDatabase().get_routing_layer_list(); + std::vector& cut_layer_list = RTDM.getDatabase().get_cut_layer_list(); + Summary& summary = RTDM.getDatabase().get_summary(); + std::string& vr_temp_directory_path = RTDM.getConfig().vr_temp_directory_path; + + std::map& routing_wire_length_map = summary.vr_summary.routing_wire_length_map; + double& total_wire_length = summary.vr_summary.total_wire_length; + std::map& cut_via_num_map = summary.vr_summary.cut_via_num_map; + int32_t& total_via_num = summary.vr_summary.total_via_num; + std::map& routing_patch_num_map = summary.vr_summary.routing_patch_num_map; + int32_t& total_patch_num = summary.vr_summary.total_patch_num; + std::map& within_net_routing_violation_num_map = summary.vr_summary.within_net_routing_violation_num_map; + int32_t& within_net_total_violation_num = summary.vr_summary.within_net_total_violation_num; + std::map& among_net_routing_violation_num_map = summary.vr_summary.among_net_routing_violation_num_map; + int32_t& among_net_total_violation_num = summary.vr_summary.among_net_total_violation_num; + std::map>& clock_timing_map = summary.vr_summary.clock_timing_map; + std::map& type_power_map = summary.vr_summary.type_power_map; + + nlohmann::json summary_json; + for (auto& [routing_layer_idx, wire_length] : routing_wire_length_map) { + summary_json["routing_wire_length_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = wire_length; + } + summary_json["total_wire_length"] = total_wire_length; + for (auto& [cut_layer_idx, via_num] : cut_via_num_map) { + summary_json["cut_via_num_map"][cut_layer_list[cut_layer_idx].get_layer_name()] = via_num; + } + summary_json["total_via_num"] = total_via_num; + for (auto& [routing_layer_idx, patch_num] : routing_patch_num_map) { + summary_json["routing_patch_num_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = patch_num; + } + summary_json["total_patch_num"] = total_patch_num; + for (auto& [routing_layer_idx, violation_num] : within_net_routing_violation_num_map) { + summary_json["within_net_routing_violation_num_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = violation_num; + } + summary_json["within_net_total_violation_num"] = within_net_total_violation_num; + for (auto& [routing_layer_idx, violation_num] : among_net_routing_violation_num_map) { + summary_json["among_net_routing_violation_num_map"][routing_layer_list[routing_layer_idx].get_layer_name()] = violation_num; + } + summary_json["among_net_total_violation_num"] = among_net_total_violation_num; + for (auto& [clock_name, timing] : clock_timing_map) { + summary_json["clock_timing_map"]["clock_name"] = clock_name; + summary_json["clock_timing_map"]["timing"] = timing; + } + for (auto& [type, power] : type_power_map) { + summary_json["type_power_map"]["type"] = type; + summary_json["type_power_map"]["power"] = power; + } + + std::string summary_json_file_path = RTUTIL.getString(vr_temp_directory_path, "summary.json"); + std::ofstream* summary_json_file = RTUTIL.getOutputFileStream(summary_json_file_path); + (*summary_json_file) << summary_json; + RTUTIL.closeFileStream(summary_json_file); + return summary_json_file_path; } #endif @@ -596,6 +666,17 @@ void ViolationReporter::debugPlotVRModel(VRModel& vr_model, std::string flag) GPGDS gp_gds; + // base_region + { + GPStruct base_region_struct("base_region"); + GPBoundary gp_boundary; + gp_boundary.set_layer_idx(0); + gp_boundary.set_data_type(0); + gp_boundary.set_rect(die.get_real_rect()); + base_region_struct.push(gp_boundary); + gp_gds.addStruct(base_region_struct); + } + // gcell_axis { GPStruct gcell_axis_struct("gcell_axis"); @@ -679,13 +760,32 @@ void ViolationReporter::debugPlotVRModel(VRModel& vr_model, std::string flag) gp_gds.addStruct(access_point_struct); } + // routing result + for (auto& [net_idx, segment_set] : RTDM.getNetGlobalResultMap(die)) { + GPStruct global_result_struct(RTUTIL.getString("global_result(net_", net_idx, ")")); + for (Segment* segment : segment_set) { + for (NetShape& net_shape : RTDM.getNetGlobalShapeList(net_idx, *segment)) { + GPBoundary gp_boundary; + gp_boundary.set_data_type(static_cast(GPDataType::kGlobalPath)); + gp_boundary.set_rect(net_shape.get_rect()); + if (net_shape.get_is_routing()) { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); + } else { + gp_boundary.set_layer_idx(RTGP.getGDSIdxByCut(net_shape.get_layer_idx())); + } + global_result_struct.push(gp_boundary); + } + } + gp_gds.addStruct(global_result_struct); + } + // routing result for (auto& [net_idx, segment_set] : RTDM.getNetDetailedResultMap(die)) { GPStruct detailed_result_struct(RTUTIL.getString("detailed_result(net_", net_idx, ")")); for (Segment* segment : segment_set) { - for (NetShape& net_shape : RTDM.getNetShapeList(net_idx, *segment)) { + for (NetShape& net_shape : RTDM.getNetDetailedShapeList(net_idx, *segment)) { GPBoundary gp_boundary; - gp_boundary.set_data_type(static_cast(GPDataType::kPath)); + gp_boundary.set_data_type(static_cast(GPDataType::kDetailedPath)); gp_boundary.set_rect(net_shape.get_rect()); if (net_shape.get_is_routing()) { gp_boundary.set_layer_idx(RTGP.getGDSIdxByRouting(net_shape.get_layer_idx())); diff --git a/src/operation/iRT/source/module/violation_reporter/ViolationReporter.hpp b/src/operation/iRT/source/module/violation_reporter/ViolationReporter.hpp index 1ba5173a09e24477cad3d9b81084da2791d11c5b..5c12bad8b0e2bc7253fca27cb34db6e24fb7bbb9 100644 --- a/src/operation/iRT/source/module/violation_reporter/ViolationReporter.hpp +++ b/src/operation/iRT/source/module/violation_reporter/ViolationReporter.hpp @@ -57,8 +57,10 @@ class ViolationReporter void printSummary(VRModel& vr_model); void outputNetCSV(VRModel& vr_model); void outputViolationCSV(VRModel& vr_model); - void outputNetJson(VRModel& vr_model); - void outputViolationJson(VRModel& vr_model); + void outputJson(VRModel& vr_model); + std::string outputNetJson(VRModel& vr_model); + std::string outputViolationJson(VRModel& vr_model); + std::string outputSummaryJson(VRModel& vr_model); #endif #if 1 // debug diff --git a/src/operation/iRT/source/toolkit/CMakeLists.txt b/src/operation/iRT/source/toolkit/CMakeLists.txt index 20e562718f13fddebc2ab5771da5c71b97fb1a5d..7289f494f2f40a0cb09a5efa63a424f1eb05030e 100644 --- a/src/operation/iRT/source/toolkit/CMakeLists.txt +++ b/src/operation/iRT/source/toolkit/CMakeLists.txt @@ -4,15 +4,15 @@ add_subdirectory(${IRT_TOOLKIT}/utility) add_library(irt_toolkit INTERFACE) -target_link_libraries(irt_toolkit +target_link_libraries(irt_toolkit INTERFACE - irt_logger - irt_monitor - irt_utility - irt_interface + irt_logger + irt_monitor + irt_utility + irt_interface ) -target_include_directories(irt_toolkit +target_include_directories(irt_toolkit INTERFACE - ${IRT_TOOLKIT} + ${IRT_TOOLKIT} ) diff --git a/src/operation/iRT/source/toolkit/logger/CMakeLists.txt b/src/operation/iRT/source/toolkit/logger/CMakeLists.txt index 2d144cce2c12d0a2543b152fc49d976290c75256..864de95b85e540924026f1a69e62b88559b204cd 100644 --- a/src/operation/iRT/source/toolkit/logger/CMakeLists.txt +++ b/src/operation/iRT/source/toolkit/logger/CMakeLists.txt @@ -1,8 +1,8 @@ -if(DEBUG_IRT_LOGGER) - message(STATUS "RT: DEBUG_IRT_LOGGER") +if(DEBUG_IRT_LOGGER) + message(STATUS "RT: DEBUG_IRT_LOGGER") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_LOGGER") + message(STATUS "RT: RELEASE_IRT_LOGGER") set(CMAKE_BUILD_TYPE "Release") endif() @@ -10,12 +10,12 @@ add_library(irt_logger ${IRT_TOOLKIT}/logger/Logger.cpp ) -target_link_libraries(irt_logger +target_link_libraries(irt_logger PUBLIC - irt_data_manager + irt_data_manager ) -target_include_directories(irt_logger +target_include_directories(irt_logger PUBLIC - ${IRT_TOOLKIT}/logger + ${IRT_TOOLKIT}/logger ) diff --git a/src/operation/iRT/source/toolkit/monitor/CMakeLists.txt b/src/operation/iRT/source/toolkit/monitor/CMakeLists.txt index a9585c40875e92e573629220fa15c98aed7b7c25..9a218174593b67cebb7ca77fbe5533b3dabeeb44 100644 --- a/src/operation/iRT/source/toolkit/monitor/CMakeLists.txt +++ b/src/operation/iRT/source/toolkit/monitor/CMakeLists.txt @@ -1,8 +1,8 @@ -if(DEBUG_IRT_MONITOR) - message(STATUS "RT: DEBUG_IRT_MONITOR") +if(DEBUG_IRT_MONITOR) + message(STATUS "RT: DEBUG_IRT_MONITOR") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_MONITOR") + message(STATUS "RT: RELEASE_IRT_MONITOR") set(CMAKE_BUILD_TYPE "Release") endif() @@ -10,12 +10,12 @@ add_library(irt_monitor ${IRT_TOOLKIT}/monitor/Monitor.cpp ) -target_link_libraries(irt_monitor +target_link_libraries(irt_monitor PUBLIC - irt_data_manager + irt_data_manager ) -target_include_directories(irt_monitor +target_include_directories(irt_monitor PUBLIC - ${IRT_TOOLKIT}/monitor + ${IRT_TOOLKIT}/monitor ) diff --git a/src/operation/iRT/source/toolkit/utility/CMakeLists.txt b/src/operation/iRT/source/toolkit/utility/CMakeLists.txt index 0453c84477712d575f89d8e23efb0de47e8bf5c5..b50c4831511d3114a9743883f0aad26554ee1042 100644 --- a/src/operation/iRT/source/toolkit/utility/CMakeLists.txt +++ b/src/operation/iRT/source/toolkit/utility/CMakeLists.txt @@ -1,8 +1,8 @@ -if(DEBUG_IRT_UTILITY) - message(STATUS "RT: DEBUG_IRT_UTILITY") +if(DEBUG_IRT_UTILITY) + message(STATUS "RT: DEBUG_IRT_UTILITY") set(CMAKE_BUILD_TYPE "Debug") else() - message(STATUS "RT: RELEASE_IRT_UTILITY") + message(STATUS "RT: RELEASE_IRT_UTILITY") set(CMAKE_BUILD_TYPE "Release") endif() @@ -10,12 +10,12 @@ add_library(irt_utility ${IRT_TOOLKIT}/utility/Utility.cpp ) -target_link_libraries(irt_utility +target_link_libraries(irt_utility PUBLIC - irt_data_manager + irt_data_manager ) -target_include_directories(irt_utility +target_include_directories(irt_utility PUBLIC - ${IRT_TOOLKIT}/utility + ${IRT_TOOLKIT}/utility ) diff --git a/src/operation/iSTA/README.md b/src/operation/iSTA/README.md index e42793d8d2f2818220bdf4ade38c52d2cb57a736..02935bd6bbdf5a5416ed6f0467c3031b7b808215 100644 --- a/src/operation/iSTA/README.md +++ b/src/operation/iSTA/README.md @@ -1,6 +1,6 @@ -# User guide of iSTA +# iSTA: Timing Analysis -> ## Introduction to the iSTA +## Introduction to the iSTA ### Software structure diagram @@ -28,7 +28,7 @@ --- -> ## Example of how to use the iSTA tool +## Example of how to use the iSTA tool ### Write the tcl file(run_ista.tcl) diff --git a/src/operation/iSTA/api/TimingEngine.cc b/src/operation/iSTA/api/TimingEngine.cc index 08eb3dddc2072e2f4ea15b8d26e74d64b514864a..e42fe9cd0e9ba0256d8c66787acb9e7732ea4776 100644 --- a/src/operation/iSTA/api/TimingEngine.cc +++ b/src/operation/iSTA/api/TimingEngine.cc @@ -395,7 +395,7 @@ void TimingEngine::resetRcTree(Net* net) { * @param id * @return RctNode* */ -RctNode* TimingEngine::makeOrFindRCTreeNode(Net* net, int id) { +RctNode* TimingEngine::makeOrFindRCTreeNode(Net* net, int64_t id) { StaBuildRCTree build_rc_tree; auto* rc_net = _timing_engine->get_ista()->getRcNet(net); if (!rc_net) { @@ -410,7 +410,7 @@ RctNode* TimingEngine::makeOrFindRCTreeNode(Net* net, int id) { } auto* rc_tree = rc_net->rct(); - std::string node_name = Str::printf("%s:%d", net->get_name(), id); + std::string node_name = Str::printf("%s:%lld", net->get_name(), id); auto* node = rc_tree->node(node_name); if (!node) { @@ -562,10 +562,13 @@ void TimingEngine::makeVirtualRCTreeResistor(const char* rc_tree_name, */ void TimingEngine::updateRCTreeInfo(Net* net) { auto* rc_net = _timing_engine->get_ista()->getRcNet(net); + if (rc_net) { rc_net->updateRcTreeInfo(); auto* rct = rc_net->rct(); if (rct) { + // check and break loop. + rc_net->checkLoop(); rct->updateRcTiming(); } } @@ -636,7 +639,7 @@ void TimingEngine::buildRcTreeAndUpdateRcTreeInfo( * @return std::map */ std::map TimingEngine::getVirtualRCTreeAllNodeSlew( - const char* rc_tree_name, double driver_slew) { + const char* rc_tree_name, double driver_slew, TransType trans_type) { if (!_virtual_rc_trees.contains(rc_tree_name)) { LOG_FATAL << "virtual RC tree " << rc_tree_name << " does not exist!"; } @@ -644,29 +647,7 @@ std::map TimingEngine::getVirtualRCTreeAllNodeSlew( auto& virtual_rc_tree = _virtual_rc_trees[rc_tree_name]; std::map all_node_slews; - auto* rc_root = virtual_rc_tree.get_root(); - - all_node_slews[rc_root->get_name()] = driver_slew; - - std::function get_snk_slew = - [&get_snk_slew, this, driver_slew, &all_node_slews](RctNode* parent_node, - RctNode* src_node) { - auto& fanout_edges = src_node->get_fanout(); - for (auto* fanout_edge : fanout_edges) { - auto& snk_node = fanout_edge->get_to(); - if (fanout_edge->isBreak() || &snk_node == parent_node) { - continue; - } - - auto snk_slew = snk_node.slew(AnalysisMode::kMax, TransType::kRise, - NS_TO_PS(driver_slew)); - all_node_slews[snk_node.get_name()] = PS_TO_NS(snk_slew); - - get_snk_slew(src_node, &snk_node); - } - }; - - get_snk_slew(nullptr, rc_root); + all_node_slews = virtual_rc_tree.getAllNodeSlew(driver_slew, AnalysisMode::kMax, trans_type); return all_node_slews; } @@ -1188,31 +1169,21 @@ double TimingEngine::getInstDelay(const char* inst_name, TransType trans_type) { auto* ista = _ista; auto* design_netlist = ista->get_netlist(); - auto* instance = design_netlist->findInstance(inst_name); + + std::string src_pin_name = Str::printf("%s:%s", inst_name, src_port_name); + auto* src_pin = design_netlist->findPin(src_pin_name.c_str(), false, true).front(); + std::string snk_pin_name = Str::printf("%s:%s", inst_name, snk_port_name); + auto* snk_pin = design_netlist->findPin(snk_pin_name.c_str(), false, true).front(); auto& the_graph = ista->get_graph(); + auto src_vertex = the_graph.findVertex(src_pin); + LOG_FATAL_IF(!src_vertex) << "src vertex " << src_pin_name << " not found "; + auto snk_vertex = the_graph.findVertex(snk_pin); + LOG_FATAL_IF(!snk_vertex) << "snk vertex " << snk_pin_name << " not found "; - Pin* pin; - int arc_delay = 0; - FOREACH_INSTANCE_PIN(instance, pin) { - if (pin->isInput()) { - auto the_vertex = the_graph.findVertex(pin); - LOG_FATAL_IF(!the_vertex); - FOREACH_SRC_ARC((*the_vertex), the_arc) { - auto* src_vertex = the_arc->get_src(); - auto* snk_vertex = the_arc->get_snk(); - std::string src_vertex_name = src_vertex->getName(); - std::string snk_vertex_name = snk_vertex->getName(); - auto* instance_arc = dynamic_cast(the_arc); + auto* instance_arc = (*src_vertex)->getSnkArc(*snk_vertex).front(); + double arc_delay = instance_arc->get_arc_delay(mode, trans_type); - if (src_vertex_name == src_port_name && - snk_vertex_name == snk_port_name) { - arc_delay = instance_arc->get_arc_delay(mode, trans_type); - break; - } - } - } - } return FS_TO_NS(arc_delay); } diff --git a/src/operation/iSTA/api/TimingEngine.hh b/src/operation/iSTA/api/TimingEngine.hh index 0e0c73d3499846729153c3c6defdd27e28091d09..3a513a39b203d306f2e0b8517d96fd129a75a62e 100644 --- a/src/operation/iSTA/api/TimingEngine.hh +++ b/src/operation/iSTA/api/TimingEngine.hh @@ -27,6 +27,7 @@ #include #include "TimingDBAdapter.hh" +#include "TimingIDBAdapter.hh" #include "sta/Sta.hh" #include "sta/StaIncremental.hh" @@ -75,6 +76,7 @@ class TimingEngine { const char *get_design_work_space() { return _ista->get_design_work_space(); } TimingDBAdapter *get_db_adapter() { return _db_adapter.get(); } + auto* getIDBAdapter() { return dynamic_cast(_db_adapter.get()); } void set_db_adapter(std::unique_ptr db_adapter); TimingEngine &readLiberty(std::vector &lib_files) { @@ -229,7 +231,7 @@ class TimingEngine { : nullptr; } void resetRcTree(Net *net); - RctNode *makeOrFindRCTreeNode(Net *net, int id); + RctNode *makeOrFindRCTreeNode(Net *net, int64_t id); RctNode *makeOrFindRCTreeNode(DesignObject *pin_or_port); RctNode *makeOrFindVirtualRCTreeNode(const char *rc_tree_name, const char *node_name); @@ -245,7 +247,7 @@ class TimingEngine { const char *net_name, std::map &loadname2wl); std::map getVirtualRCTreeAllNodeSlew( - const char* rc_tree_name, double driver_slew); + const char* rc_tree_name, double driver_slew, TransType trans_type); std::map getVirtualRCTreeAllNodeDelay( const char* rc_tree_name); @@ -274,6 +276,11 @@ class TimingEngine { return *this; } + unsigned reportWirePaths(unsigned n_worst_path_per_clock) { + _ista->set_n_worst_path_per_clock(n_worst_path_per_clock); + return _ista->reportWirePaths(); + } + std::vector getClockList(); void setPropagatedClock(const char *clock_name); bool isPropagatedClock(const char *clock_name); diff --git a/src/operation/iSTA/api/TimingIDBAdapter.cc b/src/operation/iSTA/api/TimingIDBAdapter.cc index 0658511a2ce217f5aad52d4b4333f1d16d2e2e02..9cdedc30785b021702d1d3067d0ea2d173bcd01a 100644 --- a/src/operation/iSTA/api/TimingIDBAdapter.cc +++ b/src/operation/iSTA/api/TimingIDBAdapter.cc @@ -117,13 +117,12 @@ IdbCoordinate* TimingIDBAdapter::idbLocation( * @return double Ω */ double TimingIDBAdapter::getResistance(int num_layer, double segment_length, - std::optional segment_width) { + std::optional segment_width, int routing_layer_1st) { double segment_resistance = 0; IdbLayout* idb_layout = _idb_lef_service->get_layout(); vector& routing_layers = idb_layout->get_layers()->get_routing_layers(); - int routing_layer_1st = 0; int routing_layer_id = num_layer - 1 + routing_layer_1st; int routing_layer_size = routing_layers.size(); @@ -146,18 +145,22 @@ double TimingIDBAdapter::getResistance(int num_layer, double segment_length, segment_resistance = lef_resistance * segment_length / *segment_width; #if DEBUG_TIMING_IDB _debug_csv_file << lef_resistance << "," << segment_length << "," - << *segment_width << "," << num_layer << "," - << segment_resistance << "\n"; + << *segment_width << "," << num_layer << "," + << segment_resistance << "\n"; #endif + // _debug_csv_file << lef_resistance << "," << segment_length << "," + // << *segment_width << "," << num_layer << "," + // << segment_resistance << "\n"; + return segment_resistance; } /** * @brief get segment capacitance. * - * @param num_layer layer number = target routing layer id - first routing layer - * id by data config + * @param num_layer layer number = target routing layer id - first routing + * layer id by data config * @param segment_length unit is um (micro meter) * @param segment_width unit is um (micro meter) * @return double cap unit is pf @@ -735,6 +738,7 @@ unsigned TimingIDBAdapter::convertDBToTimingNetlist(bool link_all_cell) { _ista->set_design_name(_idb_design->get_design_name().c_str()); int dbu = _idb_design->get_units()->get_micron_dbu(); + set_dbu(dbu); double width = _idb_design->get_layout()->get_die()->get_width() / static_cast(dbu); double height = _idb_design->get_layout()->get_die()->get_height() / @@ -854,7 +858,7 @@ unsigned TimingIDBAdapter::convertDBToTimingNetlist(bool link_all_cell) { return; } - std::regex re(R"(\\)"); + std::regex re(R"(\\)"); std::string net_name = std::regex_replace(raw_name, re, ""); Net* sta_net = design_netlist.findNet(net_name.c_str()); diff --git a/src/operation/iSTA/api/TimingIDBAdapter.hh b/src/operation/iSTA/api/TimingIDBAdapter.hh index f10ab9660605e60418e5a78be93c431c617307b8..0963108baa6af7ca49604d6a66de78ec216b4d31 100644 --- a/src/operation/iSTA/api/TimingIDBAdapter.hh +++ b/src/operation/iSTA/api/TimingIDBAdapter.hh @@ -57,10 +57,10 @@ using idb::IdbLayerRouting; using idb::IdbLayout; using idb::IdbLefService; using idb::IdbNet; -using idb::IdbSpecialNet; using idb::IdbNetList; using idb::IdbPin; using idb::IdbPlacementStatus; +using idb::IdbSpecialNet; using idb::IdbTerm; #define DEBUG_TIMING_IDB 0 @@ -74,7 +74,8 @@ class TimingIDBAdapter : public TimingDBAdapter { explicit TimingIDBAdapter(Sta* ista) : TimingDBAdapter(ista) { #if DEBUG_TIMING_IDB _debug_csv_file.open("debug_timing_idb.csv", std::ios_base::trunc); - _debug_csv_file << "lef_resistance,segment_length,segment_width,layer,segment_resistance" + _debug_csv_file << "lef_resistance,segment_length,segment_width,layer," + "segment_resistance" << std::endl; #endif } @@ -92,6 +93,9 @@ class TimingIDBAdapter : public TimingDBAdapter { } IdbBuilder* get_idb() const { return _idb; } + void set_dbu(int dbu) { _dbu = dbu; } + int get_dbu() const { return _dbu; } + bool isPlaced(DesignObject* pin_or_port) override; double dbuToMeters(int distance) const override; @@ -102,7 +106,7 @@ class TimingIDBAdapter : public TimingDBAdapter { IdbCoordinate* idbLocation(DesignObject* pin_or_port); double getResistance(int num_layer, double segment_length, - std::optional segment_width); + std::optional segment_width, int routing_layer_1st = 0); double getCapacitance(int num_layer, double segment_length, std::optional segment_width); double getAverageResistance(std::optional& segment_width); @@ -220,6 +224,7 @@ class TimingIDBAdapter : public TimingDBAdapter { IdbBuilder* _idb = nullptr; IdbDesign* _idb_design = nullptr; + int _dbu = 2000; IdbDefService* _idb_def_service = nullptr; IdbLefService* _idb_lef_service = nullptr; diff --git a/src/operation/iSTA/main.cc b/src/operation/iSTA/main.cc index bc03ae67752acff7ca43fd1427050b0aad851583..fbca92ba54981c01efb4f273fa8c7da924806b7a 100644 --- a/src/operation/iSTA/main.cc +++ b/src/operation/iSTA/main.cc @@ -51,6 +51,7 @@ #include "sta/StaSlewPropagation.hh" #include "tcl/UserShell.hh" #include "usage/usage.hh" +#include "time/Time.hh" DEFINE_string(confPath, "test.conf", "program configure file."); @@ -74,9 +75,12 @@ int registerCommands() { } using ieda::Stats; +using ieda::Time; int main(int argc, char** argv) { Log::init(argv); + // Start the timer + Time::start(); // for debug // Log::setVerboseLogLevel("Arnoldi*", 1); diff --git a/src/operation/iSTA/source/module/delay/ElmoreDelayCalc.cc b/src/operation/iSTA/source/module/delay/ElmoreDelayCalc.cc index dc1b2b76c0de367083e29f584ec368e4306892a4..6905e5c5c949fb140ec1ffddab25ed609bda663a 100644 --- a/src/operation/iSTA/source/module/delay/ElmoreDelayCalc.cc +++ b/src/operation/iSTA/source/module/delay/ElmoreDelayCalc.cc @@ -49,18 +49,16 @@ * @date 2021-01-27 */ #include "ElmoreDelayCalc.hh" - #include #include #include -#include "log/Log.hh" #include "liberty/Lib.hh" +#include "log/Log.hh" #include "netlist/Net.hh" #include "netlist/Pin.hh" #include "netlist/Port.hh" - namespace ista { const int THREAD_PER_BLOCK_NUM = 512; @@ -237,6 +235,10 @@ RctEdge* RcTree::insertEdge(RctNode* from_node, RctNode* to_node, double res, bool in_order) { auto& edge = _edges.emplace_back(*from_node, *to_node, res); edge.set_is_in_order(in_order); + if (from_node == to_node) { + // self loop need break; + edge.set_is_break(); + } from_node->_fanout.push_back(&edge); to_node->_fanin.push_back(&edge); @@ -262,6 +264,7 @@ void RcTree::initData() { for (auto& kvp : _str2nodes) { kvp.second._load = 0.0; + kvp.second._res = 0.0; kvp.second._delay = 0.0; kvp.second._is_update_load = 0; @@ -338,8 +341,8 @@ void RcTree::updateDelay(RctNode* parent, RctNode* from) { for (auto* e : from->_fanout) { if (auto& to = e->_to; &to != parent) { + to._res = from->_res + e->_res; to._delay = from->_delay + e->_res * to._load; - FOREACH_MODE_TRANS(mode, trans) { to._ndelay[ModeTransPair(mode, trans)] = from->_ndelay[ModeTransPair(mode, trans)] + @@ -563,6 +566,85 @@ double RcTree::slew(const std::string& name, AnalysisMode mode, return itr->second.slew(mode, trans_type, input_slew); } +/** + * @brief get wire topo of arriving to node. + * + * @param to_node_name + * @return std::vector + */ +std::vector RcTree::getWireTopo(const char* to_node_name) { + std::vector wire_topo; + + std::function get_topo_edge = + [&get_topo_edge, this, &wire_topo, to_node_name]( + RctNode* parent_node, RctNode* src_node) -> unsigned { + auto& fanout_edges = src_node->get_fanout(); + for (auto* fanout_edge : fanout_edges) { + auto& snk_node = fanout_edge->_to; + if (fanout_edge->isBreak() || &snk_node == parent_node) { + continue; + } + + if (snk_node.get_name() == to_node_name) { + wire_topo.push_back(fanout_edge); + return 1; + } + + if (get_topo_edge(src_node, &snk_node)) { + wire_topo.push_back(fanout_edge); + return 1; + } + } + + return 0; + }; + + get_topo_edge(nullptr, _root); + + LOG_FATAL_IF((wire_topo.empty() || + (*wire_topo.begin())->_to.get_name() != to_node_name)) + << "not found to node name " << to_node_name; + + return wire_topo; +} + +/** + * @brief get rc tree all node slew. + * + * @param driver_slew + * @return std::map + */ +std::map RcTree::getAllNodeSlew(double driver_slew, + AnalysisMode analysis_mode, + TransType trans_type) { + std::map all_node_slews; + auto* rc_root = get_root(); + + all_node_slews[rc_root->get_name()] = driver_slew; + + std::function get_snk_slew = + [&get_snk_slew, this, driver_slew, analysis_mode, trans_type, + &all_node_slews](RctNode* parent_node, RctNode* src_node) { + auto& fanout_edges = src_node->get_fanout(); + for (auto* fanout_edge : fanout_edges) { + auto& snk_node = fanout_edge->get_to(); + if (fanout_edge->isBreak() || &snk_node == parent_node) { + continue; + } + + auto snk_slew = + snk_node.slew(analysis_mode, trans_type, NS_TO_PS(driver_slew)); + all_node_slews[snk_node.get_name()] = PS_TO_NS(snk_slew); + + get_snk_slew(src_node, &snk_node); + } + }; + + get_snk_slew(nullptr, rc_root); + + return all_node_slews; +} + /** * @brief Print the rc tree to graphviz dot file format. * @@ -715,7 +797,8 @@ void RcTree::applyDelayDataToArray() { int parent_pos = rc_node->get_parent()->get_flatten_pos(); if (flatten_pos >= node_num) { - LOG_FATAL << "flatten pos " << flatten_pos << " is larger than node num " << node_num; + LOG_FATAL << "flatten pos " << flatten_pos + << " is larger than node num " << node_num; } parent_pos_array[flatten_pos] = parent_pos; @@ -746,24 +829,25 @@ void RcTree::applyDelayDataToArray() { } void RCNetCommonInfo::set_spef_cap_unit(const std::string& spef_cap_unit) { - // The unit is 1.0 FF, fix me - if (Str::contain(spef_cap_unit.c_str(), "1 FF") || - Str::contain(spef_cap_unit.c_str(), "1.0 FF")) { - _spef_cap_unit = CapacitiveUnit::kFF; - } else { - _spef_cap_unit = CapacitiveUnit::kPF; - } + // The unit is 1.0 FF, fix me + if (Str::contain(spef_cap_unit.c_str(), "1 FF") || + Str::contain(spef_cap_unit.c_str(), "1.0 FF")) { + _spef_cap_unit = CapacitiveUnit::kFF; + } else { + _spef_cap_unit = CapacitiveUnit::kPF; + } } -void RCNetCommonInfo::set_spef_resistance_unit(const std::string& spef_resistance_unit) { - // The unit is 1.0 OHM, fix me - if (Str::contain(spef_resistance_unit.c_str(), "1 OHM") || - Str::contain(spef_resistance_unit.c_str(), "1.0 OHM")) { - _spef_resistance_unit = ResistanceUnit::kOHM; - } else { - _spef_resistance_unit = ResistanceUnit::kOHM; - } +void RCNetCommonInfo::set_spef_resistance_unit( + const std::string& spef_resistance_unit) { + // The unit is 1.0 OHM, fix me + if (Str::contain(spef_resistance_unit.c_str(), "1 OHM") || + Str::contain(spef_resistance_unit.c_str(), "1.0 OHM")) { + _spef_resistance_unit = ResistanceUnit::kOHM; + } else { + _spef_resistance_unit = ResistanceUnit::kOHM; } +} std::string RcNet::name() const { return _net->get_name(); } size_t RcNet::numPins() const { return _net->get_pin_ports().size() - 1; } @@ -996,7 +1080,7 @@ void RcNet::updateRcTreeInfo() { auto pin_ports = _net->get_pin_ports(); // fix for net is only driver - if (pin_ports.size() < 2) { + if (pin_ports.size() < 2 || driver == nullptr) { return; } @@ -1060,7 +1144,6 @@ void RcNet::updateRcTiming(RustSpefNet* spef_net) { // rct.printGraphViz(); // } } - } /** * @brief net load @@ -1102,22 +1185,23 @@ double RcNet::load(AnalysisMode mode, TransType trans_type) { /** * @brief get slew impulse for gpu speedup data. - * - * @param mode - * @param trans_type - * @return double + * + * @param mode + * @param trans_type + * @return double */ -double RcNet::slewImpulse(DesignObject& to, AnalysisMode mode, TransType trans_type) { +double RcNet::slewImpulse(DesignObject& to, AnalysisMode mode, + TransType trans_type) { if (!rct()) { return 0.0; } - + auto* node = std::get(_rct).node(to.getFullName()); if (_rct.index() == 0) { return 0.0; } else { if (node) { - return node->_impulse[ModeTransPair{mode, trans_type}]; + return node->_impulse[ModeTransPair{mode, trans_type}]; } else { return 0.0; } @@ -1142,6 +1226,23 @@ std::set RcNet::getLoadNodes() { return load_nodes; } +/** + * @brief Get node load. + * + * @param node_name + * @return double + */ +double RcNet::getNodeLoad(const char* node_name) { + double load = 0.0; + + if (auto* rc_tree = rct(); rc_tree) { + auto* node = rc_tree->node(node_name); + load = node->_load; + } + + return load; +} + /** * @brief Get rc net resistance from driver pin to load pin. * @@ -1164,6 +1265,40 @@ double RcNet::getResistance(AnalysisMode mode, TransType trans_type, return res; } +/** + * @brief Get rc net resistance from driver pin to load pin. + * + * @param node_name + * @return double + */ +double RcNet::getNodeResistance(const char* node_name) { + double res = 0.0; + + if (auto* rc_tree = rct(); rc_tree) { + auto* node = rc_tree->node(node_name); + res = node->_res; + } + + return res; +} + +/** + * @brief Get rc net resistance. + * + * @return double + */ +double RcNet::getNetResistance() { + double res = 0.0; + + if (auto* rc_tree = rct(); rc_tree) { + for (auto& edge : rc_tree->_edges) { + res += edge.get_res(); + } + } + + return res; +} + /** * @brief get delay of rc node. * @@ -1171,12 +1306,13 @@ double RcNet::getResistance(AnalysisMode mode, TransType trans_type, * @param delay_method * @return std::optional */ -std::optional RcNet::delay(DesignObject& to, DelayMethod delay_method) { +std::optional RcNet::delay(const char* node_name, + DelayMethod delay_method) { if (_rct.index() == 0) { return std::nullopt; } - auto node = std::get(_rct).node(to.getFullName()); + auto node = std::get(_rct).node(node_name); std::optional delay; if (delay_method == DelayMethod::kElmore) { delay = node->delay(); @@ -1190,6 +1326,17 @@ std::optional RcNet::delay(DesignObject& to, DelayMethod delay_method) { return delay; } +/** + * @brief get delay of pin or port. + * + * @param to + * @param delay_method + * @return std::optional + */ +std::optional RcNet::delay(DesignObject& to, DelayMethod delay_method) { + return delay(to.getFullName().c_str()); +} + std::optional> RcNet::delay( DesignObject& to, double /* from_slew */, std::optional /* output_current */, AnalysisMode mode, @@ -1203,6 +1350,18 @@ std::optional> RcNet::delay( return std::make_pair(node->delay(mode, trans_type), waveform); } +std::optional RcNet::slew(const char* node_name, double from_slew, + AnalysisMode mode, TransType trans_type) { + if (_rct.index() == 0) { + return std::nullopt; + } + + auto* node = std::get(_rct).node(node_name); + double slew = node->slew(mode, trans_type, from_slew); + + return slew; +} + std::optional RcNet::slew( DesignObject& to, double from_slew, std::optional /* output_current */, AnalysisMode mode, @@ -1220,6 +1379,104 @@ std::optional RcNet::slew( return node->slew(mode, trans_type, from_slew); } +/** + * @brief Get all node slew based on the from driver slew. + * + * @param driver_slew + * @param mode + * @param trans_type + * @return std::map + */ +std::map& RcNet::getAllNodeSlew(double driver_slew, + AnalysisMode mode, + TransType trans_type) { + if (_all_node_slews) { + return *_all_node_slews; + } + + _all_node_slews = std::map{}; + auto* rc_tree = rct(); + if (!rc_tree) { + return _all_node_slews.value(); + } + + auto* rc_root = rc_tree->_root; + if (!rc_root) { + return _all_node_slews.value(); + } + + _all_node_slews.value()[rc_root->get_name()] = driver_slew; + + std::map all_node_slews; + + std::function get_snk_slew = + [&get_snk_slew, this, mode, trans_type, driver_slew]( + RctNode* parent_node, RctNode* src_node) { + auto& fanout_edges = src_node->get_fanout(); + for (auto* fanout_edge : fanout_edges) { + auto& snk_node = fanout_edge->_to; + if (fanout_edge->isBreak() || &snk_node == parent_node) { + continue; + } + + auto snk_slew = snk_node.slew(mode, trans_type, NS_TO_PS(driver_slew)); + _all_node_slews.value()[snk_node.get_name()] = PS_TO_NS(snk_slew); + + get_snk_slew(src_node, &snk_node); + } + }; + + get_snk_slew(nullptr, rc_root); + + return _all_node_slews.value(); +} + +/** + * @brief From the driver node, get the edges to the required node. + * + * @param to_node_name + * @return std::vector + */ +std::vector RcNet::getWireTopo(const char* to_node_name) { + std::vector wire_topo; + if (_rct.index() == 0) { + return wire_topo; + } + + std::function get_topo_edge = + [&get_topo_edge, this, &wire_topo, to_node_name]( + RctNode* parent_node, RctNode* src_node) -> unsigned { + auto& fanout_edges = src_node->get_fanout(); + for (auto* fanout_edge : fanout_edges) { + auto& snk_node = fanout_edge->_to; + if (fanout_edge->isBreak() || &snk_node == parent_node) { + continue; + } + + if (snk_node.get_name() == to_node_name) { + wire_topo.push_back(fanout_edge); + return 1; + } + + if (get_topo_edge(src_node, &snk_node)) { + wire_topo.push_back(fanout_edge); + return 1; + } + } + + return 0; + }; + + auto* rc_tree = rct(); + get_topo_edge(nullptr, rc_tree->_root); + + LOG_FATAL_IF((wire_topo.empty() || + (*wire_topo.begin())->_to.get_name() != to_node_name)) + << "not found to node name " << to_node_name; + + return wire_topo; +} + /** * @brief Print RC Tree info. * diff --git a/src/operation/iSTA/source/module/delay/ElmoreDelayCalc.hh b/src/operation/iSTA/source/module/delay/ElmoreDelayCalc.hh index 242e13787b6bb73beee68001f0cfff475be8a848..f2d565db4d759588e1149a984547439bea62c082 100644 --- a/src/operation/iSTA/source/module/delay/ElmoreDelayCalc.hh +++ b/src/operation/iSTA/source/module/delay/ElmoreDelayCalc.hh @@ -246,6 +246,7 @@ class RctNode { std::string _name; double _cap = 0.0; + double _res = 0.0; //!< from driver to node resistance. double _load = 0.0; double _delay = 0.0; double _mc = 0.0; //!< Elmore * cap @@ -546,6 +547,9 @@ class RcTree { bool isHaveCoupledNodes() { return !_coupled_nodes.empty(); } + std::vector getWireTopo(const char* to_node_name); + std::map getAllNodeSlew(double driver_slew, AnalysisMode analysis_mode, TransType trans_type); + void printGraphViz(); private: @@ -674,9 +678,15 @@ class RcNet { double load(AnalysisMode mode, TransType trans_type); double slewImpulse(DesignObject& to, AnalysisMode mode, TransType trans_type); std::set getLoadNodes(); + double getNodeLoad(const char* node_name); double getResistance(AnalysisMode mode, TransType trans_type, DesignObject* load_obj); + double getNodeResistance(const char* node_name); + double getNetResistance(); + + std::optional delay(const char* node_name, + DelayMethod delay_method = DelayMethod::kElmore); std::optional delay(DesignObject& to, DelayMethod delay_method = DelayMethod::kElmore); @@ -693,10 +703,18 @@ class RcNet { std::optional output_current, AnalysisMode mode, TransType trans_type); + std::optional slew(const char* node_name, double from_slew, + AnalysisMode mode, TransType trans_type); + virtual std::optional slew( DesignObject& to, double from_slew, std::optional output_current, AnalysisMode mode, TransType trans_type); + std::map& getAllNodeSlew(double driver_slew, + AnalysisMode mode, + TransType trans_type); + std::vector getWireTopo(const char* to_node_name); + void printRctInfo(); static void set_rc_net_common_info( @@ -717,6 +735,8 @@ class RcNet { private: static std::unique_ptr _rc_net_common_info; + + std::optional> _all_node_slews; }; #if CUDA_DELAY diff --git a/src/operation/iSTA/source/module/include/Config.hh b/src/operation/iSTA/source/module/include/Config.hh index 57152645a665f8eb8b0f68edaaf12df8157b90e0..faeb535ffa99824ed33b5071b1769fe34078851b 100644 --- a/src/operation/iSTA/source/module/include/Config.hh +++ b/src/operation/iSTA/source/module/include/Config.hh @@ -78,5 +78,7 @@ constexpr unsigned c_vertex_path_delay_data_bucket_size = 1; constexpr bool c_print_delay_yaml = false; constexpr bool c_print_net_yaml = false; +constexpr bool c_print_wire_yaml = false; +constexpr bool c_print_wire_json = true; } // namespace ista \ No newline at end of file diff --git a/src/operation/iSTA/source/module/netlist/DesignObject.hh b/src/operation/iSTA/source/module/netlist/DesignObject.hh index 91745aa51aa928435b9ad4bc479889803f3e7de6..d11c0f63e7e837eb359e0abee09d6bdd6d07ce08 100644 --- a/src/operation/iSTA/source/module/netlist/DesignObject.hh +++ b/src/operation/iSTA/source/module/netlist/DesignObject.hh @@ -108,7 +108,7 @@ class DesignObject { virtual unsigned isPinBus() { return 0; } virtual Instance* get_own_instance() { - LOG_FATAL << "The func is not defined."; + // LOG_FATAL << "The func is not defined."; return nullptr; } diff --git a/src/operation/iSTA/source/module/python-api/PythonSta.cc b/src/operation/iSTA/source/module/python-api/PythonSta.cc index 7644a0104e21f6d62257aeb3d2a18b2a023b5a26..dbfafebda0746193b51c483681bffc8445d01ae4 100644 --- a/src/operation/iSTA/source/module/python-api/PythonSta.cc +++ b/src/operation/iSTA/source/module/python-api/PythonSta.cc @@ -47,6 +47,18 @@ PYBIND11_MODULE(ista_cpp, m) { m.def("build_timing_graph", build_timing_graph); m.def("update_clock_timing", update_clock_timing); m.def("dump_graph_data", dump_graph_data, ("graph_file")); + + // get wire timing data + py::class_(m, "WireTimingData") + .def_readwrite("from_node_name", &StaWireTimingData::_from_node_name) + .def_readwrite("to_node_name", &StaWireTimingData::_to_node_name) + .def_readwrite("wire_resistance", &StaWireTimingData::_wire_resistance) + .def_readwrite("wire_capacitance", &StaWireTimingData::_wire_capacitance) + .def_readwrite("wire_from_slew", &StaWireTimingData::_wire_from_slew) + .def_readwrite("wire_to_slew", &StaWireTimingData::_wire_to_slew) + .def_readwrite("wire_delay", &StaWireTimingData::_wire_delay); + + m.def("get_wire_timing_data", get_wire_timing_data, py::arg("n_worst_path_per_clock")); } } // namespace ista diff --git a/src/operation/iSTA/source/module/python-api/PythonSta.hh b/src/operation/iSTA/source/module/python-api/PythonSta.hh index e00a5e9a988396f9be7081e7f115c0a82957fb7d..633d3d5d5c893e982b3c65ea07a1dc8625e8e49a 100644 --- a/src/operation/iSTA/source/module/python-api/PythonSta.hh +++ b/src/operation/iSTA/source/module/python-api/PythonSta.hh @@ -216,7 +216,7 @@ std::vector get_used_libs() { /** * @brief Only build timing graph. - * + * */ void build_timing_graph() { auto* ista = ista::Sta::getOrCreateSta(); @@ -225,21 +225,35 @@ void build_timing_graph() { /** * @brief Only update clock timing. - * + * */ void update_clock_timing() { auto* ista = ista::Sta::getOrCreateSta(); - ista->updateClockTiming(); + ista->updateClockTiming(); } /** * @brief Print the graph in yaml format. - * - * @param graph_file + * + * @param graph_file */ void dump_graph_data(std::string graph_file) { auto* ista = ista::Sta::getOrCreateSta(); ista->dumpGraphData(graph_file.c_str()); } +/** + * @brief Get the wire timing data object. + * + * @param n_worst_path_per_clock + * @return std::vector + */ +std::vector get_wire_timing_data( + unsigned n_worst_path_per_clock) { + auto* ista = ista::Sta::getOrCreateSta(); + auto path_wire_timing_data = ista->reportTimingData(n_worst_path_per_clock); + + return path_wire_timing_data; +} + } // namespace ista diff --git a/src/operation/iSTA/source/module/sta/CMakeLists.txt b/src/operation/iSTA/source/module/sta/CMakeLists.txt index 7b4ff0567fb56a6b808804108916b5200f9e9ba4..6992e8c6011fcc8e08fb376b501b76226c5114ee 100644 --- a/src/operation/iSTA/source/module/sta/CMakeLists.txt +++ b/src/operation/iSTA/source/module/sta/CMakeLists.txt @@ -31,4 +31,6 @@ target_link_libraries(sta delay-gpu propagation-gpu ) -endif() \ No newline at end of file +endif() + +set(CMAKE_BUILD_TYPE "Debug") \ No newline at end of file diff --git a/src/operation/iSTA/source/module/sta/Sta.cc b/src/operation/iSTA/source/module/sta/Sta.cc index 87effdda10fac1f538da6ce15f048d57d07f325e..2caf3c6a0294daddbdd4a446743315ab7daf47cd 100644 --- a/src/operation/iSTA/source/module/sta/Sta.cc +++ b/src/operation/iSTA/source/module/sta/Sta.cc @@ -94,8 +94,8 @@ Sta::Sta() _clock_groups(sta_clock_cmp) { char config[] = "iSTA"; char *argv[] = {config, nullptr}; - // We need to initialize the log system here, because Sta() may be called in pybind, - // which does not have a main function to initialize the log system. + // We need to initialize the log system here, because Sta() may be called in + // pybind, which does not have a main function to initialize the log system. Log::init(argv); _report_tbl_summary = StaReportPathSummary::createReportTable("sta"); @@ -343,8 +343,8 @@ unsigned Sta::linkLibertys() { } auto link_lib = [this](auto &lib_rust_reader) { - // master should load all lib. - // lib_rust_reader.set_build_cells(get_link_cells()); + // master should load all lib cell. + lib_rust_reader.set_build_cells(get_link_cells()); lib_rust_reader.linkLib(); auto lib = lib_rust_reader.get_library_builder()->takeLib(); @@ -1807,7 +1807,8 @@ void Sta::setReportSpec(std::vector &&prop_froms, * @param rpt_file_name The report text file name. * @return unsigned 1 if success, 0 else fail. */ -unsigned Sta::reportPath(const char *rpt_file_name, bool is_derate /*=true*/) { +unsigned Sta::reportPath(const char *rpt_file_name, bool is_derate, + bool only_wire_path) { auto report_path = [this](StaReportPathSummary &report_path_func) -> unsigned { unsigned is_ok = 1; @@ -1831,7 +1832,7 @@ unsigned Sta::reportPath(const char *rpt_file_name, bool is_derate /*=true*/) { return is_ok; }; - auto report_path_of_mode = [&report_path, this, rpt_file_name, + auto report_path_of_mode = [&report_path, this, rpt_file_name, only_wire_path, is_derate](AnalysisMode mode) -> unsigned { unsigned is_ok = 1; if ((get_analysis_mode() == mode) || @@ -1860,6 +1861,16 @@ unsigned Sta::reportPath(const char *rpt_file_name, bool is_derate /*=true*/) { report_funcs.emplace_back(&report_path_dump); } + StaReportWirePathYaml report_wire_dump(rpt_file_name, mode, n_worst); + if (c_print_wire_yaml) { + report_funcs.emplace_back(&report_wire_dump); + } + + StaReportWirePathJson report_wire_dump_json(rpt_file_name, mode, n_worst); + if (c_print_wire_json) { + report_funcs.emplace_back(&report_wire_dump_json); + } + StaReportPathDetailJson report_path_detail_json(rpt_file_name, mode, n_worst, is_derate); @@ -1868,10 +1879,17 @@ unsigned Sta::reportPath(const char *rpt_file_name, bool is_derate /*=true*/) { } for (auto *report_fun : report_funcs) { - is_ok = report_path(*report_fun); + if (only_wire_path) { + if (dynamic_cast(report_fun)) { + is_ok = report_path(*report_fun); + } + + } else { + is_ok = report_path(*report_fun); + } } } - + return is_ok; }; @@ -2172,11 +2190,8 @@ double Sta::getWNS(const char *clock_name, AnalysisMode mode) { FOREACH_PATH_END_DATA(path_end, mode, path_data) { seq_data_queue.push(path_data); } - - if (!seq_data_queue.empty()) { - auto *worst_seq_data = seq_data_queue.top(); - WNS = FS_TO_NS(worst_seq_data->getSlack()); - } + auto *worst_seq_data = seq_data_queue.top(); + WNS = FS_TO_NS(worst_seq_data->getSlack()); break; } } @@ -2794,35 +2809,6 @@ unsigned Sta::resetPathData() { return 1; } -#if CUDA_PROPAGATION -unsigned Sta::resetGPUData() { - _gpu_vertices.clear(); - _gpu_arcs.clear(); - - GPU_Flatten_Data flatten_data; - _flatten_data = std::move(flatten_data); - - GPU_Graph gpu_graph; - _gpu_graph = std::move(gpu_graph); - - _lib_gpu_arcs.clear(); - - free_lib_data_gpu(_gpu_lib_data, _lib_gpu_tables, _lib_gpu_table_ptrs); - - Lib_Data_GPU gpu_lib_data; - _gpu_lib_data = std::move(gpu_lib_data); - - _lib_gpu_tables.clear(); - _lib_gpu_table_ptrs.clear(); - - _arc_to_index.clear(); - _at_to_index.clear(); - _index_to_at.clear(); - - return 1; -} -#endif - /** * @brief update the timing data. * @@ -3087,17 +3073,57 @@ unsigned Sta::reportTiming(std::set &&exclude_cell_names /*= {}*/, reportUsedLibs(); + // for test dump timing data in memory. + // reportTimingData(10); + + // for test dump json data. + // reportWirePaths(); + #if CUDA_PROPAGATION - printFlattenData(); + // printFlattenData(); #endif // dumpGraphData("/home/taosimin/ysyx_test25/2025-04-05/graph.yaml"); LOG_INFO << "The timing engine run success."; + // restart the timer. + Time::start(); + return 1; } +/** + * @brief report timing data in memory for online analysis. + * + * @param n_worst_path_per_clock + * @return unsigned + */ +std::vector Sta::reportTimingData( + unsigned n_worst_path_per_clock) { + LOG_INFO << "get wire timing start"; + std::vector path_timing_data; + + set_n_worst_path_per_clock(n_worst_path_per_clock); + + for (auto analysi_mode : {AnalysisMode::kMax, AnalysisMode::kMin}) { + StaReportPathTimingData report_path_timing_data_func( + nullptr, analysi_mode, n_worst_path_per_clock); + for (auto &[capture_clock, seq_path_group] : _clock_groups) { + auto group_timing_data = + report_path_timing_data_func.getPathGroupTimingData( + seq_path_group.get()); + path_timing_data.insert(path_timing_data.end(), group_timing_data.begin(), + group_timing_data.end()); + } + } + + LOG_INFO << "the wire timing data size: " << path_timing_data.size(); + LOG_INFO << "get wire timing end"; + + return path_timing_data; +} + /** * @brief report used libs. * @@ -3106,11 +3132,37 @@ unsigned Sta::reportTiming(std::set &&exclude_cell_names /*= {}*/, unsigned Sta::reportUsedLibs() { auto used_libs = getUsedLibs(); for (auto *used_lib : used_libs) { - const char *lib_name = used_lib->get_file_name(); - if (lib_name) { - LOG_INFO << "used lib: " << lib_name; + std::string lib_name = used_lib->get_file_name(); + LOG_INFO << "used lib: " << lib_name; + } + return 1; +} + +/** + * @brief report wire paths. + * + * @return unsigned + */ +unsigned Sta::reportWirePaths() { + LOG_INFO << "report wire paths start"; + const char *design_work_space = get_design_work_space(); + + std::string path_dir = std::string(design_work_space) + "/wire_paths"; + + if (std::filesystem::exists(path_dir)) { + for (const auto &entry : std::filesystem::directory_iterator(path_dir)) { + if (entry.is_regular_file()) { + std::filesystem::remove(entry.path()); + } } } + + std::string rpt_file_name = + Str::printf("%s/%s.rpt", design_work_space, get_design_name().c_str()); + reportPath(rpt_file_name.c_str(), false, true); + + LOG_INFO << "report wire paths end"; + return 1; } diff --git a/src/operation/iSTA/source/module/sta/Sta.hh b/src/operation/iSTA/source/module/sta/Sta.hh index a4a7b9fab483c21ada3df9c6b21b8df1aa7616e8..90931e53af6dbc7ecadd0e29388d549c8acb5d14 100644 --- a/src/operation/iSTA/source/module/sta/Sta.hh +++ b/src/operation/iSTA/source/module/sta/Sta.hh @@ -506,7 +506,7 @@ class Sta { } auto& get_report_spec() { return _report_spec; } - unsigned reportPath(const char* rpt_file_name, bool is_derate = true); + unsigned reportPath(const char* rpt_file_name, bool is_derate = true, bool only_wire_path = false); unsigned reportTrans(const char* rpt_file_name); unsigned reportCap(const char* rpt_file_name, bool is_clock_cap); unsigned reportFanout(const char* rpt_file_name); @@ -582,7 +582,10 @@ class Sta { unsigned reportTiming(std::set&& exclude_cell_names = {}, bool is_derate = false, bool is_clock_cap = false, bool is_copy = true); + + std::vector reportTimingData(unsigned n_worst_path_per_clock); unsigned reportUsedLibs(); + unsigned reportWirePaths(); void dumpVertexData(std::vector vertex_names); void dumpNetlistData(); diff --git a/src/operation/iSTA/source/module/sta/StaAnalyze.cc b/src/operation/iSTA/source/module/sta/StaAnalyze.cc index 7d6322079018c2900a8589a053405fa74cf42f36..9e87304b4ee9f89d56b9314697e804ed0fed3a6f 100644 --- a/src/operation/iSTA/source/module/sta/StaAnalyze.cc +++ b/src/operation/iSTA/source/module/sta/StaAnalyze.cc @@ -562,7 +562,7 @@ unsigned StaAnalyze::operator()(StaGraph* the_graph) { unsigned index = 0; FOREACH_END_VERTEX(the_graph, end_vertex) { ++index; - LOG_INFO_EVERY_N(10) << "analyze timing path end vertex " << index + LOG_INFO_EVERY_N(1000) << "analyze timing path end vertex " << index << " total " << the_graph->get_end_vertexes().size() << " start"; if (end_vertex->is_start() && end_vertex->is_end()) { diff --git a/src/operation/iSTA/source/module/sta/StaClockSlewDelayPropagation.cc b/src/operation/iSTA/source/module/sta/StaClockSlewDelayPropagation.cc index 23af0ed2b82d86acb7abaaccb55bcdf46c39b12f..3dfb65af56a1f4bbc7c1220f1618558f81c92b8e 100644 --- a/src/operation/iSTA/source/module/sta/StaClockSlewDelayPropagation.cc +++ b/src/operation/iSTA/source/module/sta/StaClockSlewDelayPropagation.cc @@ -76,7 +76,8 @@ unsigned StaClockSlewDelayPropagation::operator()(StaVertex* the_vertex) { continue; } - if (src_arc->isInstArc() && !src_arc->get_snk()->get_design_obj()->get_net()) { + if (src_arc->isInstArc() && + !src_arc->get_snk()->get_design_obj()->get_net()) { // skip the instance output not connected to the net. continue; } diff --git a/src/operation/iSTA/source/module/sta/StaDump.cc b/src/operation/iSTA/source/module/sta/StaDump.cc index 58f5972129d7e18c35132e4fd725f28659370480..9f248857ddba6467ff4283e50ac09b52817331b4 100644 --- a/src/operation/iSTA/source/module/sta/StaDump.cc +++ b/src/operation/iSTA/source/module/sta/StaDump.cc @@ -22,13 +22,15 @@ * @date 2021-04-22 */ +#include "StaDump.hh" + #include #include +#include #include #include -#include "StaDump.hh" #include "ThreadPool/ThreadPool.h" namespace ista { @@ -305,6 +307,179 @@ unsigned StaDumpDelayYaml::operator()(StaArc* the_arc) { return 1; } +/** + * @brief dump timing vertex data for AI EDA dataset. + * + * @param the_vertex + * @return unsigned + */ +unsigned StaDumpWireYaml::operator()(StaVertex* the_vertex) { + AnalysisMode analysis_mode = _analysis_mode; + TransType trans_type = _trans_type; + + unsigned& node_id = _node_id; + std::string node_name = Str::printf("node_%d", node_id++); + _file << node_name << ":\n"; + + _file << " Point: " << the_vertex->getNameWithCellName() << "\n"; + auto vertex_load = the_vertex->getLoad(analysis_mode, trans_type); + _file << " Capacitance: " << vertex_load << "\n"; + auto vertex_slew = the_vertex->getSlewNs(analysis_mode, trans_type); + _file << " slew: " << (vertex_slew ? *vertex_slew : 0.0) << "\n"; + _file << " trans_type: " + << ((trans_type == TransType::kRise) ? "rise" : "fall") << "\n"; + + return 1; +} + +/** + * @brief dump timing arc data, for net arc, we need extract the wire topo, from + * driver pin to load pin. + * @param the_arc + * @return unsigned + */ +unsigned StaDumpWireYaml::operator()(StaArc* the_arc) { + AnalysisMode analysis_mode = _analysis_mode; + TransType trans_type = _trans_type; + + auto vertex_slew = the_arc->get_src()->getSlewNs(analysis_mode, trans_type); + + unsigned& arc_id = _arc_id; + const char* arc_type_str = the_arc->isNetArc() ? "net" : "inst"; + std::string node_name = Str::printf("%s_arc_%d", arc_type_str, arc_id++); + _file << node_name << ":\n"; + + _file << " Incr: " + << FS_TO_NS(the_arc->get_arc_delay(analysis_mode, trans_type)) << "\n"; + + if (the_arc->isNetArc()) { + // for net arc, we need extract the wire topo. + auto* the_net_arc = dynamic_cast(the_arc); + auto* the_net = the_net_arc->get_net(); + + auto* rc_net = getSta()->getRcNet(the_net); + if ((rc_net == nullptr) || (rc_net->rct() == nullptr)) { + return 0; + } + auto* snk_node = the_arc->get_snk(); + auto snk_node_name = snk_node->get_design_obj()->getFullName(); + + auto wire_topo = rc_net->getWireTopo(snk_node_name.c_str()); + auto& all_nodes_slew = + rc_net->getAllNodeSlew(*vertex_slew, analysis_mode, trans_type); + for (int edge_index = 0; + auto* wire_edge : wire_topo | std::ranges::views::reverse) { + std::string edge_index_name = Str::printf("edge_%d", edge_index++); + + _file << " " << edge_index_name << ":\n"; + + auto& from_node = wire_edge->get_from(); + auto& to_node = wire_edge->get_to(); + + _file << " wire_from_node: " << from_node.get_name() << "\n"; + _file << " wire_to_node: " << to_node.get_name() << "\n"; + _file << " wire_R: " << wire_edge->get_res() << "\n"; + _file << " wire_C: " << (from_node.nodeLoad() - to_node.nodeLoad()) + << "\n"; + _file << " from_slew: " << all_nodes_slew[from_node.get_name()] + << "\n"; + _file << " to_slew: " << all_nodes_slew[to_node.get_name()] << "\n"; + _file << " wire_delay: " + << PS_TO_NS(to_node.delay() - from_node.delay()) << "\n"; + } + } + + return 1; +} + +/** + * @brief dump timing vertex data in json. + * + * @param the_vertex + * @return unsigned + */ +unsigned StaDumpWireJson::operator()(StaVertex* the_vertex) { + AnalysisMode analysis_mode = _analysis_mode; + TransType trans_type = _trans_type; + + json vertex_data; + + unsigned& node_id = _node_id; + std::string node_name = Str::printf("node_%d", node_id++); + vertex_data[node_name]["Point"] = the_vertex->getNameWithCellName(); + auto vertex_load = the_vertex->getLoad(analysis_mode, trans_type); + vertex_data[node_name]["Capacitance"] = vertex_load; + auto vertex_slew = the_vertex->getSlewNs(analysis_mode, trans_type); + vertex_data[node_name]["slew"] = vertex_slew ? *vertex_slew : 0.0; + vertex_data[node_name]["trans_type"] = + (trans_type == TransType::kRise) ? "rise" : "fall"; + + _parent_json.push_back(vertex_data); + + return 1; +} + +/** + * @brief dump timing arc data in json. + * + * @param the_arc + * @return unsigned + */ +unsigned StaDumpWireJson::operator()(StaArc* the_arc) { + AnalysisMode analysis_mode = _analysis_mode; + TransType trans_type = _trans_type; + + auto vertex_slew = the_arc->get_src()->getSlewNs(analysis_mode, trans_type); + + unsigned& arc_id = _arc_id; + const char* arc_type_str = the_arc->isNetArc() ? "net" : "inst"; + std::string arc_name = Str::printf("%s_arc_%d", arc_type_str, arc_id++); + + json arc_data; + arc_data[arc_name]["Incr"] = + FS_TO_NS(the_arc->get_arc_delay(analysis_mode, trans_type)); + if (the_arc->isNetArc()) { + // for net arc, we need extract the wire topo. + auto* the_net_arc = dynamic_cast(the_arc); + auto* the_net = the_net_arc->get_net(); + + auto* rc_net = getSta()->getRcNet(the_net); + if ((rc_net == nullptr) || (rc_net->rct() == nullptr)) { + return 0; + } + auto* snk_node = the_arc->get_snk(); + auto snk_node_name = snk_node->get_design_obj()->getFullName(); + + auto wire_topo = rc_net->getWireTopo(snk_node_name.c_str()); + auto& all_nodes_slew = + rc_net->getAllNodeSlew(*vertex_slew, analysis_mode, trans_type); + for (int edge_index = 0; + auto* wire_edge : wire_topo | std::ranges::views::reverse) { + std::string edge_index_name = Str::printf("edge_%d", edge_index++); + + auto& from_node = wire_edge->get_from(); + auto& to_node = wire_edge->get_to(); + + arc_data[arc_name][edge_index_name]["wire_from_node"] = + from_node.get_name(); + arc_data[arc_name][edge_index_name]["wire_to_node"] = to_node.get_name(); + arc_data[arc_name][edge_index_name]["wire_R"] = wire_edge->get_res(); + arc_data[arc_name][edge_index_name]["wire_C"] = + (from_node.nodeLoad() - to_node.nodeLoad()); + arc_data[arc_name][edge_index_name]["from_slew"] = + all_nodes_slew[from_node.get_name()]; + arc_data[arc_name][edge_index_name]["to_slew"] = + all_nodes_slew[to_node.get_name()]; + arc_data[arc_name][edge_index_name]["wire_delay"] = + PS_TO_NS(to_node.delay() - from_node.delay()); + } + } + + _parent_json.push_back(arc_data); + + return 1; +} + /** * @brief Print Graph in GraphViz dot format. * @@ -355,4 +530,68 @@ unsigned StaDumpGraphViz::operator()(StaGraph* the_graph) { return 1; } +/** + * @brief dump the timing data of the timing arc. + * + * @param the_arc + * @return unsigned + */ +unsigned StaDumpTimingData::operator()(StaArc* the_arc) { + AnalysisMode analysis_mode = _analysis_mode; + TransType trans_type = _trans_type; + + auto vertex_slew = the_arc->get_src()->getSlewNs(analysis_mode, trans_type); + if (the_arc->isInstArc()) { + double inst_arc_delay = + FS_TO_NS(the_arc->get_arc_delay(analysis_mode, trans_type)); + + StaWireTimingData wire_timing_data; + wire_timing_data._from_node_name = the_arc->get_src()->getName(); + wire_timing_data._to_node_name = the_arc->get_snk()->getName(); + wire_timing_data._wire_from_slew = vertex_slew.value_or(0.0); + wire_timing_data._wire_to_slew = + the_arc->get_snk()->getSlewNs(analysis_mode, trans_type).value_or(0.0); + wire_timing_data._wire_delay = inst_arc_delay; + + _wire_timing_datas.emplace_back(wire_timing_data); + } else { + // for net arc, we need extract the wire topo. + auto* the_net_arc = dynamic_cast(the_arc); + auto* the_net = the_net_arc->get_net(); + + auto* rc_net = getSta()->getRcNet(the_net); + if ((rc_net == nullptr) || (rc_net->rct() == nullptr)) { + return 0; + } + + auto* rc_tree = rc_net->rct(); + auto* snk_node = the_arc->get_snk(); + auto snk_node_name = snk_node->get_design_obj()->getFullName(); + + auto wire_topo = rc_tree->getWireTopo(snk_node_name.c_str()); + auto all_nodes_slew = + rc_tree->getAllNodeSlew(*vertex_slew, analysis_mode, trans_type); + for (auto* wire_edge : wire_topo | std::ranges::views::reverse) { + auto& from_node = wire_edge->get_from(); + auto& to_node = wire_edge->get_to(); + + StaWireTimingData wire_timing_data; + + wire_timing_data._from_node_name = from_node.get_name(); + wire_timing_data._to_node_name = to_node.get_name(); + wire_timing_data._wire_resistance = wire_edge->get_res(); + wire_timing_data._wire_capacitance = + from_node.nodeLoad() - to_node.nodeLoad(); + wire_timing_data._wire_from_slew = all_nodes_slew[from_node.get_name()]; + wire_timing_data._wire_to_slew = all_nodes_slew[to_node.get_name()]; + wire_timing_data._wire_delay = + PS_TO_NS(to_node.delay() - from_node.delay()); + + _wire_timing_datas.emplace_back(wire_timing_data); + } + } + + return 1; +} + } // namespace ista \ No newline at end of file diff --git a/src/operation/iSTA/source/module/sta/StaDump.hh b/src/operation/iSTA/source/module/sta/StaDump.hh index 0b5a9fb4418374b98db588b79a6251aa3ca2b491..4c6008956153771e8b50936aae0e7776b9b190d6 100644 --- a/src/operation/iSTA/source/module/sta/StaDump.hh +++ b/src/operation/iSTA/source/module/sta/StaDump.hh @@ -24,6 +24,7 @@ #pragma once #include +#include "json/json.hpp" #include "StaFunc.hh" @@ -68,7 +69,7 @@ class StaDumpDelayYaml : public StaDumpYaml { unsigned operator()(StaVertex* the_vertex) override; unsigned operator()(StaArc* the_arc) override; - private: + protected: AnalysisMode _analysis_mode; TransType _trans_type; @@ -76,6 +77,56 @@ class StaDumpDelayYaml : public StaDumpYaml { unsigned _arc_id = 0; }; +/** + * @brief The class for dump wire data in yaml text file for training data. + * + */ +class StaDumpWireYaml : public StaDumpDelayYaml { + public: + StaDumpWireYaml(std::ofstream& file) : _file(file) {} + ~StaDumpWireYaml() override = default; + + void set_analysis_mode(AnalysisMode analysis_mode) { + _analysis_mode = analysis_mode; + } + AnalysisMode get_analysis_mode() override { return _analysis_mode; } + + void set_trans_type(TransType trans_type) { _trans_type = trans_type; } + auto get_trans_type() { return _trans_type; } + + unsigned operator()(StaVertex* the_vertex) override; + unsigned operator()(StaArc* the_arc) override; + + private: + std::ofstream& _file; +}; + +/** + * @brief The class for dump wire data in json text file for training data. + * + */ +class StaDumpWireJson : public StaDumpDelayYaml { + public: + + using json = nlohmann::ordered_json; + StaDumpWireJson(json& parent_json) : _parent_json(parent_json) {} + ~StaDumpWireJson() override = default; + + void set_analysis_mode(AnalysisMode analysis_mode) { + _analysis_mode = analysis_mode; + } + AnalysisMode get_analysis_mode() override { return _analysis_mode; } + + void set_trans_type(TransType trans_type) { _trans_type = trans_type; } + auto get_trans_type() { return _trans_type; } + + unsigned operator()(StaVertex* the_vertex) override; + unsigned operator()(StaArc* the_arc) override; + + private: + json& _parent_json; +}; + /** * @brief The class for dump sta data in graphviz format for GUI show. * @@ -85,4 +136,26 @@ class StaDumpGraphViz : public StaFunc { unsigned operator()(StaGraph* the_graph) override; }; +/** + * @brief The class for dump timing data in memory for python call. + * + */ +class StaDumpTimingData : public StaFunc { + public: + unsigned operator()(StaArc* the_arc) override; + + void set_analysis_mode(AnalysisMode mode) { _analysis_mode = mode; } + AnalysisMode get_analysis_mode() { return _analysis_mode; } + void set_trans_type(TransType trans_type) { _trans_type = trans_type; } + TransType get_trans_type() { return _trans_type; } + + auto get_wire_timing_datas() { return _wire_timing_datas; } + + private: + std::vector _wire_timing_datas; + + AnalysisMode _analysis_mode; + TransType _trans_type; +}; + } // namespace ista diff --git a/src/operation/iSTA/source/module/sta/StaReport.cc b/src/operation/iSTA/source/module/sta/StaReport.cc index 7f5e4b13cc7bdaf4208c086c685c11a625e0b9fd..86d5d93e88e43ce0aa381accb3a4352b9f17d1fa 100644 --- a/src/operation/iSTA/source/module/sta/StaReport.cc +++ b/src/operation/iSTA/source/module/sta/StaReport.cc @@ -29,8 +29,8 @@ #include #include #include -#include #include +#include #include "Sta.hh" #include "StaDump.hh" @@ -334,22 +334,24 @@ unsigned StaReportPathDetail::operator()(StaSeqPathData* seq_path_data) { #if CUDA_PROPAGATION auto& at_to_index = ista->get_at_to_index(); -#else - std::map at_to_index; +#else + std::map at_to_index; #endif - auto print_path_data = [&report_tbl, &fix_point_str, &is_derate, &at_to_index]( - auto& path_stack, auto clock_path_arrive_time) { + auto print_path_data = [&report_tbl, &fix_point_str, &is_derate, + &at_to_index](auto& path_stack, + auto clock_path_arrive_time) { double last_arrive_time = 0; StaVertex* last_vertex = nullptr; while (!path_stack.empty()) { auto* path_delay_data = path_stack.top(); std::string path_delay_index_str; #if CUDA_PROPAGATION - unsigned gpu_at_index = at_to_index[dynamic_cast(path_delay_data)]; + unsigned gpu_at_index = + at_to_index[dynamic_cast(path_delay_data)]; path_delay_index_str = Str::printf("(GPU AT %d)", gpu_at_index); #endif - + auto* own_vertex = path_delay_data->get_own_vertex(); auto trans_type = path_delay_data->get_trans_type(); auto delay_type = path_delay_data->get_delay_type(); @@ -928,8 +930,7 @@ unsigned StaReportPathDump::operator()(StaSeqPathData* seq_path_data) { path_stack.pop(); } - std::string design_work_space = - dump_yaml.getSta()->get_design_work_space(); + std::string design_work_space = dump_yaml.getSta()->get_design_work_space(); std::string path_dir = design_work_space + "/path"; std::filesystem::create_directories(path_dir); @@ -995,6 +996,163 @@ unsigned StaReportPathYaml::operator()(StaSeqPathData* seq_path_data) { return 1; } +StaReportWirePathYaml::StaReportWirePathYaml(const char* rpt_file_name, + AnalysisMode analysis_mode, + unsigned n_worst) + : StaReportPathDump(rpt_file_name, analysis_mode, n_worst) {} + +/** + * @brief print timing path in yaml in wire level. + * + * @param seq_path_data + * @return unsigned + */ +unsigned StaReportWirePathYaml::operator()(StaSeqPathData* seq_path_data) { + // CPU_PROF_START(0); + std::string design_work_space = + ista::Sta::getOrCreateSta()->get_design_work_space(); + std::string path_dir = design_work_space + "/wire_paths"; + + std::filesystem::create_directories(path_dir); + + static unsigned file_id = 1; + std::string now_time = Time::getNowWallTime(); + std::string tmp = Str::replace(now_time, ":", "_"); + std::string text_file_name = Str::printf( + "%s/wire_path_%s_%d.yml", path_dir.c_str(), tmp.c_str(), file_id++); + + std::ofstream file(text_file_name, std::ios::trunc); + StaDumpWireYaml dump_wire_yaml(file); + std::stack path_stack = seq_path_data->getPathDelayData(); + + StaVertex* last_vertex = nullptr; + while (!path_stack.empty()) { + auto* path_delay_data = path_stack.top(); + auto* own_vertex = path_delay_data->get_own_vertex(); + dump_wire_yaml.set_analysis_mode(path_delay_data->get_delay_type()); + dump_wire_yaml.set_trans_type(path_delay_data->get_trans_type()); + + if (last_vertex) { + auto snk_arcs = last_vertex->getSnkArc(own_vertex); + auto* snk_arc = snk_arcs.empty() ? nullptr : snk_arcs.front(); + snk_arc->exec(dump_wire_yaml); + } + + own_vertex->exec(dump_wire_yaml); + + last_vertex = own_vertex; + + path_stack.pop(); + } + + file.close(); + + LOG_INFO << "output yaml file path: " << text_file_name; + + // CPU_PROF_END(0, "dump one timing path wire yaml"); + + return 1; +} + +StaReportWirePathJson::StaReportWirePathJson(const char* rpt_file_name, + AnalysisMode analysis_mode, + unsigned n_worst) + : StaReportPathDump(rpt_file_name, analysis_mode, n_worst) {} + +/** + * @brief print timing path in json in wire level. + * + * @param seq_path_data + * @return unsigned + */ +unsigned StaReportWirePathJson::operator()(StaSeqPathData* seq_path_data) { + // CPU_PROF_START(0); + std::string design_work_space = + ista::Sta::getOrCreateSta()->get_design_work_space(); + std::string path_dir = design_work_space + "/wire_paths"; + + std::filesystem::create_directories(path_dir); + + static unsigned file_id = 1; + std::string text_file_name = Str::printf( + "%s/wire_path_%d.json", path_dir.c_str(), file_id++); + + json path_json = json::array(); + StaDumpWireJson dump_wire_json(path_json); + std::stack path_stack = seq_path_data->getPathDelayData(); + + StaVertex* last_vertex = nullptr; + while (!path_stack.empty()) { + auto* path_delay_data = path_stack.top(); + auto* own_vertex = path_delay_data->get_own_vertex(); + dump_wire_json.set_analysis_mode(path_delay_data->get_delay_type()); + dump_wire_json.set_trans_type(path_delay_data->get_trans_type()); + + if (last_vertex) { + auto snk_arcs = last_vertex->getSnkArc(own_vertex); + auto* snk_arc = snk_arcs.empty() ? nullptr : snk_arcs.front(); + snk_arc->exec(dump_wire_json); + } + + own_vertex->exec(dump_wire_json); + + last_vertex = own_vertex; + + path_stack.pop(); + } + + std::ofstream file(text_file_name, std::ios::trunc); + file << path_json.dump(4) << std::endl; + + file.close(); + + LOG_INFO << "output json file path: " << text_file_name; + + // CPU_PROF_END(0, "dump one timing path wire yaml"); + return 1; + +} + +StaReportPathTimingData::StaReportPathTimingData(const char* rpt_file_name, + AnalysisMode analysis_mode, + unsigned n_worst) + : StaReportPathSummary(rpt_file_name, analysis_mode, n_worst) {} + +/** + * @brief report path timing data in memory for python call. + * + * @param seq_path_data + * @return unsigned + */ +unsigned StaReportPathTimingData::operator()(StaSeqPathData* seq_path_data) { + StaDumpTimingData dump_timing_data; + + std::stack path_stack = seq_path_data->getPathDelayData(); + + StaVertex* last_vertex = nullptr; + while (!path_stack.empty()) { + auto* path_delay_data = path_stack.top(); + auto* own_vertex = path_delay_data->get_own_vertex(); + dump_timing_data.set_analysis_mode(path_delay_data->get_delay_type()); + dump_timing_data.set_trans_type(path_delay_data->get_trans_type()); + + if (last_vertex) { + auto snk_arcs = last_vertex->getSnkArc(own_vertex); + auto* snk_arc = snk_arcs.empty() ? nullptr : snk_arcs.front(); + snk_arc->exec(dump_timing_data); + } + + last_vertex = own_vertex; + + path_stack.pop(); + } + + auto wire_timing_datas = dump_timing_data.get_wire_timing_datas(); + set_path_timing_data(std::move(wire_timing_datas)); + + return 1; +} + StaReportTrans::StaReportTrans(const char* rpt_file_name, AnalysisMode analysis_mode, unsigned n_worst) : _rpt_file_name(Str::copy(rpt_file_name)), diff --git a/src/operation/iSTA/source/module/sta/StaReport.hh b/src/operation/iSTA/source/module/sta/StaReport.hh index ab10d80fe797ff2d6c570816acf9dd61100c1baa..569cdc6cc996800e12e6d046d9cea0a56324ad9d 100644 --- a/src/operation/iSTA/source/module/sta/StaReport.hh +++ b/src/operation/iSTA/source/module/sta/StaReport.hh @@ -26,6 +26,7 @@ #include +#include "json/json.hpp" #include "StaPathData.hh" #include "report/ReportTable.hh" @@ -67,6 +68,7 @@ class StaReportPathSummary { [[nodiscard]] unsigned get_significant_digits() const { return _significant_digits; } + auto get_analysis_mode() const { return _analysis_mode; } void set_significant_digits(unsigned significant_digits) { _significant_digits = significant_digits; } @@ -81,11 +83,11 @@ class StaReportPathSummary { virtual unsigned operator()(StaSeqPathGroup* seq_path_group); private: - const char* _rpt_file_name; //!< The report file name. - AnalysisMode _analysis_mode; //!< The max/min analysis mode. - unsigned _n_worst; //!< The top n path num. - unsigned _significant_digits = 3; //!< The significant digits. - bool _json_report_enabled = false; //!< The flag to dump json file. + const char* _rpt_file_name; //!< The report file name. + AnalysisMode _analysis_mode; //!< The max/min analysis mode. + unsigned _n_worst; //!< The top n path num. + unsigned _significant_digits = 3; //!< The significant digits. + bool _json_report_enabled = false; //!< The flag to dump json file. }; /** @@ -172,6 +174,89 @@ class StaReportPathYaml : public StaReportPathDump { unsigned operator()(StaSeqPathData* seq_path_data) override; }; +/** + * @brief The wire timing data, wire maybe instance arc or net wire segment. + * + */ +struct StaWireTimingData { + std::string _from_node_name; + std::string _to_node_name; + double _wire_resistance = 0.0; + double _wire_capacitance = 0.0; + double _wire_from_slew = 0.0; + double _wire_to_slew = 0.0; + double _wire_delay = 0.0; +}; + +using StaPathWireTimingData = std::vector; + +/** + * @brief The report timing data for python api call. + * + */ +class StaReportPathTimingData : public StaReportPathSummary { + public: + StaReportPathTimingData(const char* rpt_file_name, AnalysisMode analysis_mode, + unsigned n_worst); + ~StaReportPathTimingData() override = default; + + void set_path_timing_data(std::vector path_timing_data) { + _path_timing_data = std::move(path_timing_data); + } + auto& get_path_timing_data() { return _path_timing_data; } + + unsigned operator()(StaSeqPathData* seq_path_data) override; + + std::vector getPathGroupTimingData( + StaSeqPathGroup* seq_path_group) { + std::vector path_timing_data; + + StaPathEnd* path_end; + StaPathData* path_data; + AnalysisMode analysis_mode = get_analysis_mode(); + FOREACH_PATH_GROUP_END(seq_path_group, path_end) + FOREACH_PATH_END_DATA(path_end, analysis_mode, path_data) { + (*this)(dynamic_cast(path_data)); + path_timing_data.push_back(std::move(_path_timing_data)); + } + return path_timing_data; + } + + private: + std::vector _path_timing_data; +}; + +/** + * @brief The report wire path in yaml format. + * + */ +class StaReportWirePathYaml : public StaReportPathDump { + public: + StaReportWirePathYaml(const char* rpt_file_name, AnalysisMode analysis_mode, + unsigned n_worst); + ~StaReportWirePathYaml() override = default; + + unsigned operator()(StaSeqPathData* seq_path_data) override; +}; + +/** + * @brief The report wire path in json format. + * + */ +class StaReportWirePathJson : public StaReportPathDump { + public: + StaReportWirePathJson(const char* rpt_file_name, AnalysisMode analysis_mode, + unsigned n_worst); + ~StaReportWirePathJson() override = default; + + using json = nlohmann::ordered_json; + + unsigned operator()(StaSeqPathData* seq_path_data) override; + + private: + json _json; +}; + /** * @brief The DRV trans report. * diff --git a/src/operation/iSTA/test/DelayGpuTest.cc b/src/operation/iSTA/test/DelayGpuTest.cc index 1026b6d5c3fcf1f53bac2c1e1904bdaae8d72230..61aa810a39af098dc6746f2e8f2338528dc48f8a 100644 --- a/src/operation/iSTA/test/DelayGpuTest.cc +++ b/src/operation/iSTA/test/DelayGpuTest.cc @@ -97,7 +97,7 @@ TEST_F(DelayGPUTest, skywater130) { LOG_INFO << "netlist net num : " << timing_engine->get_netlist()->getNetNum(); } -TEST_F(DelayGPUTest, T28) { +TEST_F(DelayGPUTest, commerical) { Stats stats; auto* timing_engine = TimingEngine::getOrCreateTimingEngine(); @@ -105,72 +105,7 @@ TEST_F(DelayGPUTest, T28) { const char* design_work_space = "/home/longshuaiying/cuda_delay"; timing_engine->set_design_work_space(design_work_space); - std::vector lib_files{ - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp30p140hvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp30p140lvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp30p140mblvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp30p140mbssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp30p140opphvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp30p140opplvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp30p140oppssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp30p140oppuhvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp30p140oppulvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp30p140ssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp30p140uhvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp30p140ulvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp35p140hvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp35p140lvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp35p140mbhvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp35p140mblvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp35p140mbssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp35p140opphvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp35p140opplvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp35p140oppssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp35p140oppuhvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp35p140oppulvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp35p140ssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp35p140uhvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp35p140ulvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp40p140ehvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp40p140hvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp40p140lvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp40p140mbhvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp40p140mbssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp40p140oppehvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp40p140opphvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp40p140opplvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp40p140oppssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp40p140oppuhvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/tcbn28hpcplusbwp40p140ssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "tcbn28hpcplusbwp40p140uhvtssg0p81v125c_ccs.lib", - "/home/taosimin/T28/ccslib/" - "ts5n28hpcplvta256x32m4fw_130a_ssg0p81v125c.lib", - "/home/taosimin/T28/ccslib/" - "ts5n28hpcplvta64x128m2fw_130a_ssg0p81v125c.lib", - "/home/taosimin/T28/ccslib/tphn28hpcpgv18ssg0p81v1p62v125c.lib", - "/home/taosimin/T28/ccslib/PLLTS28HPMLAINT_SS_0P81_125C.lib"}; + std::vector lib_files{}; timing_engine->readLiberty(lib_files); timing_engine->get_ista()->set_analysis_mode(ista::AnalysisMode::kMaxMin); @@ -178,12 +113,12 @@ TEST_F(DelayGPUTest, T28) { timing_engine->get_ista()->set_top_module_name("asic_top"); - timing_engine->readDesign("/home/taosimin/T28/tapout/asic_top_1220.v"); + timing_engine->readDesign("asic_top_1220.v"); timing_engine->linkDesign("asic_top"); - timing_engine->readSdc("/home/taosimin/T28/ieda_1204/asic_top_SYN_MAX.sdc"); + timing_engine->readSdc("asic_top_SYN_MAX.sdc"); - timing_engine->readSpef("/home/taosimin/T28/spef/asic_top.rcworst.125c.spef"); + timing_engine->readSpef("asic_top.rcworst.125c.spef"); LOG_INFO << "netlist instance num : " << timing_engine->get_netlist()->getInstanceNum(); LOG_INFO << "netlist net num : " << timing_engine->get_netlist()->getNetNum(); diff --git a/src/operation/iSTA/test/DelayTest.cc b/src/operation/iSTA/test/DelayTest.cc index 80b1417c8864c03806599597a630a90a6feb54a0..8ef69fa8709037d93e44d1cdb08fa5de55074cf4 100755 --- a/src/operation/iSTA/test/DelayTest.cc +++ b/src/operation/iSTA/test/DelayTest.cc @@ -78,7 +78,7 @@ TEST_F(DelayTest, virtual_rc_tree) { std::cout << node_name << ": " << delay << std::endl; } - auto node_slews = timing_engine->getVirtualRCTreeAllNodeSlew("virtual_rc_tree", 0.002); + auto node_slews = timing_engine->getVirtualRCTreeAllNodeSlew("virtual_rc_tree", 0.002, TransType::kRise); for (auto& [node_name, slew] : node_slews) { std::cout << node_name << ": " << slew << std::endl; } diff --git a/src/operation/iTO/README.md b/src/operation/iTO/README.md index 50ecafacfe6ac5c1ec2f7b11258e116dad317f68..a0c29d41a9c67c90ab14a4e8e139e35e5b9b0326 100644 --- a/src/operation/iTO/README.md +++ b/src/operation/iTO/README.md @@ -1,96 +1,93 @@ -# iTO 功能文档 +# iTO: Timing Optimization -> ## 概述 +## Overview -TO的全称为Timing Optimization,时序优化。在该步骤,EDA工具会根据时序约束文件,对芯片进行时序分析,目的是通过单元尺寸调整和插入缓冲器等方法尽可能地修复芯片存在的时序违例。 +The full name of TO is Timing Optimization. In this step, the EDA tool performs timing analysis on the chip according to the timing constraint file. The purpose is to repair the timing violations of the chip as much as possible by methods such as cell sizing and buffer insertion. -时序违例检查主要包括: -1. 时序设计规则违例(DRV)检查; -2. 建立时间违例(Setup)检查; -3. 保持时间违例(Hold)检查。 +The main checks for timing violations include: +1. Timing design rule violation (DRV) check; +2. Setup time violation check; +3. Hold time violation check. -支持功能: -1. 时序设计规则违例(DRV)优化; -2. 建立时间违例(Setup)优化; -3. 保持时间违例(Hold)优化。 +Supported functions: +1. Timing design rule violation (DRV) optimization; +2. Setup time violation optimization; +3. Hold time violation optimization. -iTO提供了4个Tcl命令: -1. `run_to`:由用户在config文件中任意指定需要优化的步骤; -2. `run_to_drv`:执行DRV优化; -2. `run_to_hold`:执行Hold优化; -2. `run_to_setup`:执行Setup优化。 +iTO provides 4 Tcl commands: +1. `run_to`: Users can arbitrarily specify the optimization steps needed in the config file; +2. `run_to_drv`: Perform DRV optimization; +2. `run_to_hold`: Perform Hold optimization; +2. `run_to_setup`: Perform Setup optimization. -> ## iTO使用示例 +## iTO Usage Example -部分Config说明 +Part of the Config description ``` -"routing_tree": "flute", // 连接线网所有引脚的topology,主要用于RC树构建,DRV优化,以及Setup优化。可选flute:flute构建的rsmt、hvtree:HV tree、shallow-light:通过SALT构建的shallow-light tree -"setup_target_slack": 0.0, // setup slack小于该值时认为违例,也是slack优化的目标 -"hold_target_slack": 0.4, // hold slack小于该值时认为违例,也是slack优化的目标 -"max_insert_instance_percent": 0.2, // 缓冲器插入的面积占芯片面积的最大比例 -"max_core_utilization": 0.8, // 缓冲器插入后的面积+其他单元的面积,占芯片面积的最大比例 +"setup_slack_margin": 0.0, // When the setup slack is less than this value, it is considered a violation and is also the target of slack optimization +"hold_slack_margin": 0.4, // When the hold slack is less than this value, it is considered a violation and is also the target of slack optimization +"max_buffer_percent": 0.2, // The maximum proportion of the area occupied by buffer insertion to the chip area +"max_utilization": 0.8, // The maximum proportion of the area after buffer insertion + the area of other cells to the chip area "DRV_insert_buffers": [ - "" // 优化DRV使用的缓冲器 + "" // Buffers used for optimizing DRV ], "setup_insert_buffers": [ - "" // 优化setup使用的缓冲器 + "" // Buffers used for optimizing setup ], "hold_insert_buffers": [ - "" // 优化hold使用的缓冲器 + "" // Buffers used for optimizing hold ], -"number_of_decreasing_slack_iter": 5, // 迭代优化setup时,允许WNS不断变差的最大连续迭代次数 -"max_allowed_buffering_fanout": 20, // 针对setup,线网的fanout超过该值时不会对其进行缓冲器插入优化 -"min_divide_fanout": 8 // 针对setup,线网的fanout大于该值时通过插入缓冲器把fanout降低 -"optimize_endpoints_percent": 1.0 //针对setup,需要优化的违例端点占全部违例端点的比例 -"drv_optimize_iter_number": 5 // 针对drv,drv优化的执行次数 +"number_passes_allowed_decreasing_slack": 5, // When iteratively optimizing setup, the maximum consecutive number of iterations allowed for WNS to continuously deteriorate +"rebuffer_max_fanout": 20, // For setup, when the fanout of a net exceeds this value, buffer insertion optimization will not be performed on it +"split_load_min_fanout": 8 // For setup, when the fanout of a net is greater than this value, the fanout is reduced by inserting buffers ``` -iTO可以独立执行某个优化步骤,也可以任意指定需要优化的步骤。 -需要执行哪个步骤,可将iTO的Config文件中对应的步骤设置为True +iTO can perform a certain optimization step independently or arbitrarily specify the steps to be optimized. +To perform which step, set the corresponding step in the iTO Config file to True ``` "optimize_drv": false, "optimize_hold": false, "optimize_setup": false, ``` -下面以执行DRV优化为例: +The following takes performing DRV optimization as an example: -1.在Tcl文件中设置Config文件 +1. Set the Config file in the Tcl file -`run_to_drv -config ./iEDA_config/to_default_config_drv.json` +`run_to_drv -config./iEDA_config/to_default_config_drv.json` -2.使用iEDA运行tcl文件 +2. Use iEDA to run the tcl file -`./iEDA -script ./script/iTO_script/run_iTO_drv.tcl` +`./iEDA -script./script/iTO_script/run_iTO_drv.tcl` -### 报告输出 +### Report Output -在Config文件中可设置优化结果的报告输出路径: +The report output path of the optimization result can be set in the Config file: ``` "report_file": "path" ``` -DRV优化报告示例: +Example of DRV optimization report: ``` Found 0 slew violations. Found 0 capacitance violations. Found 0 fanout violations. Found 0 long wires. -Before ViolationFix | slew_vio: 0 cap_vio: 0 fanout_vio: 0 length_vio: 0 \\ 优化前违例情况 +Before ViolationFix | slew_vio: 0 cap_vio: 0 fanout_vio: 0 length_vio: 0 \\ Violation situation before optimization The 1th check -After ViolationFix | slew_vio: 0 cap_vio: 0 fanout_vio: 0 length_vio: 0 \\ 优化后违例情况 +After ViolationFix | slew_vio: 0 cap_vio: 0 fanout_vio: 0 length_vio: 0 \\ Violation situation after optimization Inserted 0 buffers in 0 nets. Resized 0 instances. ``` -Hold优化报告示例: +Example of Hold optimization report: ``` -// 优化前Hold违例情况。 +// Hold violation situation before optimization. --------------------------------------------------------------------------- Clock Group Hold TNS Hold WNS --------------------------------------------------------------------------- @@ -104,7 +101,7 @@ Worst Hold Path Capture: dpath/a_reg/_145_:CLK Finish hold optimization! Total inserted 0 hold buffers and 0 load buffers. -// 优化后Hold违例情况。 +// Hold violation situation after optimization. --------------------------------------------------------------------------- Clock Group Hold TNS Hold WNS --------------------------------------------------------------------------- @@ -112,9 +109,9 @@ core_clock 0 0 --------------------------------------------------------------------------- ``` -Setup优化报告示例: +Example of Setup optimization report: ``` --0.304023 -0.204023 // setup优化过程中的WNS变化情况 +-0.304023 -0.204023 // WNS changes during setup optimization Inserted 10 buffers. Resized 10 instances. Unable to repair all setup violations. diff --git a/src/platform/data_manager/config/dm_config.h b/src/platform/data_manager/config/dm_config.h index 3348d7905da2ca3e64423ce4deef6edb1537c043..e2e42cf2db6b694782ebbdd9713d5d084465bc1f 100644 --- a/src/platform/data_manager/config/dm_config.h +++ b/src/platform/data_manager/config/dm_config.h @@ -68,6 +68,7 @@ class DataConfig vector& get_lib_paths() { return _lib_paths; } string& get_sdc_path() { return _sdc_path; } string& get_spef_path() { return _spef_path; } + string& get_feature_path() { return _feature_path;} /// settings string& get_routing_layer_1st() { return _settings.routing_layer_1st; } @@ -119,6 +120,12 @@ class DataConfig std::cout << "[Data config set] spef = " << _spef_path << std::endl; } + void set_feature_path(const string feature_path) + { + _feature_path = feature_path; + std::cout << "[Data config set] feature = " << _feature_path << std::endl; + } + void set_routing_layer_1st(string layer) { _settings.routing_layer_1st = layer; } /// function @@ -138,6 +145,7 @@ class DataConfig vector _lib_paths; string _sdc_path; string _spef_path; + string _feature_path; LayerSettings _settings; }; diff --git a/src/platform/data_manager/idm.h b/src/platform/data_manager/idm.h index 8b1885f7fc758b111da0e526ec5e0325ed584f93..fd27c3cc22654b5858ef8a7062149e68d2a7f465 100644 --- a/src/platform/data_manager/idm.h +++ b/src/platform/data_manager/idm.h @@ -47,7 +47,7 @@ using std::vector; using namespace idb; -#define dmInst idm::DataManager::getInstance() //dmInst is DataManager* +#define dmInst idm::DataManager::getInstance() // dmInst is DataManager* namespace idm { @@ -65,16 +65,12 @@ class DataManager /// getter DataConfig& get_config() { return _config; }; IdbBuilder* get_idb_builder() { return _idb_builder; } - void set_idb_builder(IdbBuilder* idb_builder) { - _idb_builder = idb_builder; - } + void set_idb_builder(IdbBuilder* idb_builder) { _idb_builder = idb_builder; } IdbDefService* get_idb_def_service() { return _idb_def_service; } - void set_idb_def_service(IdbDefService* idb_def_service) { - _idb_def_service = idb_def_service; - } + void set_idb_def_service(IdbDefService* idb_def_service) { _idb_def_service = idb_def_service; } IdbLefService* get_idb_lef_service() { return _idb_lef_service; } void set_idb_lef_service(IdbLefService* idb_lef_service) { _idb_lef_service = idb_lef_service; } - + IdbDesign* get_idb_design() { return _idb_def_service != nullptr ? _idb_def_service->get_design() : nullptr; } IdbLayout* get_idb_layout() { return _idb_lef_service != nullptr ? _idb_lef_service->get_layout() : nullptr; } bool is_def_read() { return _idb_def_service != nullptr ? true : false; } @@ -208,7 +204,8 @@ class DataManager // bool buildPA(const std::map>>& master_access_point_map); // std::vector getMasterPaPointList(std::string master_name, std::string pin_name); // std::vector getInstancePaPointList(std::string instance_name, std::string pin_name); - // std::vector getInstancePaPointList(std::string cell_master_name, std::string pin_name, int32_t inst_x, int32_t inst_y, + // std::vector getInstancePaPointList(std::string cell_master_name, std::string pin_name, int32_t inst_x, int32_t + // inst_y, // idb::IdbOrient idb_orient); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/platform/flow/config/flow_config.cpp b/src/platform/flow/config/flow_config.cpp index c6fec46d781cd14ee9018fb90b6928aeeaacebdb..7c74b80961ff5d9a14fe7256d357f20340e93e89 100644 --- a/src/platform/flow/config/flow_config.cpp +++ b/src/platform/flow/config/flow_config.cpp @@ -42,18 +42,6 @@ bool PLFConfig::initConfig(string path) { nlohmann::json json; config_stream >> json; - /// read tools option - _tools_config.run_tcl = ieda::getJsonData(json, {"Tools", "TCL"}); - - /// read flow - _flow_config.run_synthesis = ieda::getJsonData(json, {"Flow", "Synthesis"}); - _flow_config.run_floorplan = ieda::getJsonData(json, {"Flow", "Floorplan"}); - _flow_config.run_placer = ieda::getJsonData(json, {"Flow", "Placer"}); - _flow_config.run_cts = ieda::getJsonData(json, {"Flow", "CTS"}); - _flow_config.run_router = ieda::getJsonData(json, {"Flow", "Router"}); - _flow_config.run_drc = ieda::getJsonData(json, {"Flow", "DRC"}); - _flow_config.run_gui = ieda::getJsonData(json, {"Flow", "GUI"}); - _flow_config.run_to = ieda::getJsonData(json, {"Flow", "TO"}); /// read config path _config_path.idb_path = ieda::getJsonData(json, {"ConfigPath", "idb_path"}); @@ -63,6 +51,7 @@ bool PLFConfig::initConfig(string path) _config_path.irt_path = ieda::getJsonData(json, {"ConfigPath", "irt_path"}); _config_path.idrc_path = ieda::getJsonData(json, {"ConfigPath", "idrc_path"}); _config_path.ito_path = ieda::getJsonData(json, {"ConfigPath", "ito_path"}); + _config_path.ipnp_path = ieda::getJsonData(json, {"ConfigPath", "ipnp_path"}); } ieda::closeFileStream(config_stream); diff --git a/src/platform/flow/config/flow_config.h b/src/platform/flow/config/flow_config.h index 3c631b8c759f819399eb691619441f8c78da006f..89e717df0dfc4a86d3c3f3e5884b0eec613f967e 100644 --- a/src/platform/flow/config/flow_config.h +++ b/src/platform/flow/config/flow_config.h @@ -31,24 +31,6 @@ using std::vector; namespace iplf { #define flowConfigInst PLFConfig::getInstance() -struct ToolsConfig -{ - string run_tcl; -}; - -struct FlowConfig -{ - string run_synthesis; - string run_floorplan; - string run_placer; - string run_cts; - string run_router; - string run_pa; - string run_drc; - string run_gui; - string run_to; -}; - struct ConfigPath { string idb_path; @@ -58,6 +40,7 @@ struct ConfigPath string idrc_path; string icts_path; string ito_path; + string ipnp_path; }; struct EnvironmentInfo @@ -80,12 +63,6 @@ class PLFConfig static PLFConfig* getInstance() { if (_instance == nullptr) { - // _mutex.lock(); - // if (_instance == NULL) { - // _instance = new PLFConfig(); - // } - // _mutex.unlock(); - _instance = new PLFConfig(); } @@ -95,19 +72,6 @@ class PLFConfig /// getter string get_path() { return _path; } - bool is_flow_running(string flag) { return flag == "ON" ? true : false; } - - bool is_run_tcl() { return is_flow_running(_tools_config.run_tcl); } - - bool is_run_synthesis() { return is_flow_running(_flow_config.run_synthesis); } - bool is_run_floorplan() { return is_flow_running(_flow_config.run_floorplan); } - bool is_run_placer() { return is_flow_running(_flow_config.run_placer); } - bool is_run_cts() { return is_flow_running(_flow_config.run_cts); } - bool is_run_router() { return is_flow_running(_flow_config.run_router); } - bool is_run_drc() { return is_flow_running(_flow_config.run_drc); } - bool is_run_gui() { return is_flow_running(_flow_config.run_gui); } - bool is_run_to() { return is_flow_running(_flow_config.run_to); } - string get_idb_path() { return _config_path.idb_path; } string get_ifp_path() { return _config_path.ifp_path; } string get_ipl_path() { return _config_path.ipl_path; } @@ -115,6 +79,7 @@ class PLFConfig string get_irt_path() { return _config_path.irt_path; } string get_idrc_path() { return _config_path.idrc_path; } string get_ito_path() { return _config_path.ito_path; } + string get_ipnp_path() { return _config_path.ipnp_path; } FlowStatus& get_status() { return _status; } string get_status_stage() { return _status.stage; } @@ -146,8 +111,6 @@ class PLFConfig // static std::mutex _mutex; string _path = ""; - ToolsConfig _tools_config; - FlowConfig _flow_config; ConfigPath _config_path; FlowStatus _status; EnvironmentInfo _env_info; diff --git a/src/platform/flow/flow.cpp b/src/platform/flow/flow.cpp index 118c2397a41a3503c7819e4c83bde506d87b48bc..da784611d3d5d6d0833bc1dcc195303bdadb2cf7 100644 --- a/src/platform/flow/flow.cpp +++ b/src/platform/flow/flow.cpp @@ -54,11 +54,7 @@ bool Flow::initFlow(string flow_config) void Flow::run(int argc, char** argv) { - if (PLFConfig::getInstance()->is_run_tcl()) { - runTcl(argc, argv); - } else { - runFlow(); - } + runTcl(argc, argv); } void Flow::runTcl(int argc, char** argv) @@ -66,58 +62,4 @@ void Flow::runTcl(int argc, char** argv) tcl::tcl_start(argc, argv); } -void Flow::runFlow() -{ - /// init DB - if (tmInst->idbStart(PLFConfig::getInstance()->get_idb_path())) { - } - - /// run fp - /// fp autorun depends on fp_config, which has to be verified - // if (PLFConfig::getInstance()->is_run_floorplan()) { - // if (tmInst->autoRunFloorplan(PLFConfig::getInstance()->get_ifp_path())) { } - // } - - /// run placer - if (PLFConfig::getInstance()->is_run_placer()) { - if (tmInst->autoRunPlacer(PLFConfig::getInstance()->get_ipl_path())) { - } - } - - /// run TO - if (PLFConfig::getInstance()->is_run_to()) { - if (tmInst->autoRunTO(PLFConfig::getInstance()->get_ito_path())) { - } - } - - /// run cts - if (PLFConfig::getInstance()->is_run_cts()) { - if (tmInst->autoRunCTS(PLFConfig::getInstance()->get_icts_path())) { - } - } - - /// run router - if (PLFConfig::getInstance()->is_run_router()) { - if (tmInst->autoRunRouter(PLFConfig::getInstance()->get_irt_path())) { - } - } - - /// run filler - if (PLFConfig::getInstance()->is_run_placer()) { - if (tmInst->runPlacerFiller(PLFConfig::getInstance()->get_ipl_path())) { - } - } - - /// run DRC - if (PLFConfig::getInstance()->is_run_drc()) { - if (tmInst->autoRunDRC(PLFConfig::getInstance()->get_idrc_path())) { - } - } - - /// run gui - if (PLFConfig::getInstance()->is_run_gui()) { - tmInst->guiStart(); - } -} - } // namespace iplf diff --git a/src/platform/flow/flow.h b/src/platform/flow/flow.h index f8854cdf69127b2c9a6e40fbce553e03d7b8d803..f8b762a9cebddd680ada8cef6d01583907768a74 100644 --- a/src/platform/flow/flow.h +++ b/src/platform/flow/flow.h @@ -50,7 +50,6 @@ class Flow bool initFlow(string flow_config = ""); void run(int argc, char** argv); - void runFlow(); void runTcl(int argc, char** argv); private: diff --git a/src/platform/tool_manager/CMakeLists.txt b/src/platform/tool_manager/CMakeLists.txt index a1b9ec4b35779990b307fb3fe3709c210f1ef501..96db84739a80f6e4bf07d5e16c0f97f459b20887 100644 --- a/src/platform/tool_manager/CMakeLists.txt +++ b/src/platform/tool_manager/CMakeLists.txt @@ -11,6 +11,7 @@ add_subdirectory(tool_api/idrc_io) add_subdirectory(tool_api/ipl_io) add_subdirectory(tool_api/ito_io) add_subdirectory(tool_api/ino_io) +add_subdirectory(tool_api/ipnp_io) add_library(tool_manager tool_manager.cpp @@ -33,8 +34,8 @@ target_link_libraries(tool_manager tool_api_ipw tool_api_ito tool_api_ino - - ipl-api + tool_api_ipnp + ivec_db ) target_link_libraries(tool_manager PUBLIC idm) diff --git a/src/platform/tool_manager/tool_api/idrc_io/idrc_io.h b/src/platform/tool_manager/tool_api/idrc_io/idrc_io.h index fef6a1420af654e10583e8e1c38ffcdf5d275c12..4bf95bff65bb0a3a7f96fb7d50d3a99ed862edc4 100644 --- a/src/platform/tool_manager/tool_api/idrc_io/idrc_io.h +++ b/src/platform/tool_manager/tool_api/idrc_io/idrc_io.h @@ -25,7 +25,7 @@ namespace iplf { -#define drcInst (DrcIO::getInstance()) +#define drcInst DrcIO::getInstance() class DrcIO { public: diff --git a/src/platform/tool_manager/tool_api/ipl_io/ipl_io.cpp b/src/platform/tool_manager/tool_api/ipl_io/ipl_io.cpp index 659d9fe0866eb3a3dff715ce50b5ab2a68dcb4b6..f5f64ca5b93029c661c97aa6cc6db0525476b9be 100644 --- a/src/platform/tool_manager/tool_api/ipl_io/ipl_io.cpp +++ b/src/platform/tool_manager/tool_api/ipl_io/ipl_io.cpp @@ -261,7 +261,7 @@ bool PlacerIO::runIncrementalFlow(std::string config) iPLAPIInst.runIncrementalFlow(); - iPLAPIInst.destoryInst(); + // iPLAPIInst.destoryInst(); flowConfigInst->add_status_runtime(stats.elapsedRunTime()); flowConfigInst->set_status_memmory(stats.memoryDelta()); diff --git a/src/platform/tool_manager/tool_api/ipnp_io/CMakeLists.txt b/src/platform/tool_manager/tool_api/ipnp_io/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7487181db1d17a3b26afb19302db69797a401019 --- /dev/null +++ b/src/platform/tool_manager/tool_api/ipnp_io/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library(tool_api_ipnp + ipnp_io.cpp +) + +target_include_directories(tool_api_ipnp + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(tool_api_ipnp + PRIVATE + flow_config + ipnp_api +) diff --git a/src/platform/tool_manager/tool_api/ipnp_io/ipnp_io.cpp b/src/platform/tool_manager/tool_api/ipnp_io/ipnp_io.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f174e2768657d750803b9de94e9f3fd8cea15c39 --- /dev/null +++ b/src/platform/tool_manager/tool_api/ipnp_io/ipnp_io.cpp @@ -0,0 +1,47 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#include "ipnp_io.h" + +#include + +#include "flow_config.h" +#include "ipnp_api.hh" +#include "usage/usage.hh" + +namespace iplf { +PnpIO* PnpIO::_instance = nullptr; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool PnpIO::runPNP(std::string config) +{ + flowConfigInst->set_status_stage("iPNP - Power Network Planning"); + + ieda::Stats stats; + + PNPApiInst->run_pnp(config); + + std::cout << "iPNP completed successfully" << std::endl; + + flowConfigInst->add_status_runtime(stats.elapsedRunTime()); + flowConfigInst->set_status_memmory(stats.memoryDelta()); + + return true; +} + +} // namespace iplf diff --git a/src/platform/tool_manager/tool_api/ipnp_io/ipnp_io.h b/src/platform/tool_manager/tool_api/ipnp_io/ipnp_io.h new file mode 100644 index 0000000000000000000000000000000000000000..9834ff8db9a19ee3ce477042524b9e03174b456b --- /dev/null +++ b/src/platform/tool_manager/tool_api/ipnp_io/ipnp_io.h @@ -0,0 +1,42 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once + +#include + +namespace iplf { +#define pnpInst PnpIO::getInstance() + +class PnpIO { + public: + static PnpIO* getInstance() { + if (!_instance) { + _instance = new PnpIO; + } + return _instance; + } + + bool runPNP(std::string config = ""); + + private: + static PnpIO* _instance; + + PnpIO() = default; + ~PnpIO() = default; +}; + +} // namespace iplf diff --git a/src/platform/tool_manager/tool_manager.cpp b/src/platform/tool_manager/tool_manager.cpp index a49314964ac1bf04f8854ab878133aa14cfbf7e7..83f6654a075ba53bf02d34c8f1974df22c68ab85 100644 --- a/src/platform/tool_manager/tool_manager.cpp +++ b/src/platform/tool_manager/tool_manager.cpp @@ -24,6 +24,7 @@ #include "ifp_io.h" #include "ino_io.h" #include "ipl_io.h" +#include "ipnp_io.h" #include "ipw_io.h" #include "irt_io.h" #include "ista_io.h" @@ -130,6 +131,13 @@ void ToolManager::guiShowClockTree() guiInst->readClockTreeDb(ctsInst->get_node_list()); #endif } + +void ToolManager::guiShowGraph(std::map graph) +{ +#ifdef BUILD_GUI + guiInst->readGraphDb(graph); +#endif +} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -334,4 +342,10 @@ bool ToolManager::autoRunPower(std::string config) return powerInst->autoRunPower(config); } +/// iPNP +bool ToolManager::autoRunPNP(std::string config) +{ + return pnpInst->runPNP(config); +} + } // namespace iplf diff --git a/src/platform/tool_manager/tool_manager.h b/src/platform/tool_manager/tool_manager.h index b0a0030d3292d4220c4e582f072a6685134ab06b..11ce74f3cbf949887a11eabf6a47a901a8fb52a5 100644 --- a/src/platform/tool_manager/tool_manager.h +++ b/src/platform/tool_manager/tool_manager.h @@ -31,6 +31,8 @@ #include #include +#include "vec_net.h" + namespace iplf { #define tmInst ToolManager::getInstance() @@ -64,6 +66,7 @@ class ToolManager void guiReadDb(); void guiShowDrc(std::string detail_drc_path = "", int max_num = 100000); void guiShowClockTree(); + void guiShowGraph(std::map graph); void guiCaptrueDesign(std::string path = ""); /// Eval @@ -113,6 +116,9 @@ class ToolManager /// iPW bool autoRunPower(std::string config = ""); + /// iPNP + bool autoRunPNP(std::string config = ""); + bool buildClockTree(std::string config = "", std::string data_path = ""); bool saveClockTree(std::string data_path); @@ -121,7 +127,6 @@ class ToolManager ToolManager(); ~ToolManager() = default; - /// }; } // namespace iplf diff --git a/.clang-tidy b/src/utility/.clang-tidy old mode 100644 new mode 100755 similarity index 100% rename from .clang-tidy rename to src/utility/.clang-tidy diff --git a/src/utility/CMakeLists.txt b/src/utility/CMakeLists.txt index 750c71a43a9a21e147b1a35ceee0f3eea6ebc2ef..113815575f5e6d117f4720d0385db09dfafd8ac2 100644 --- a/src/utility/CMakeLists.txt +++ b/src/utility/CMakeLists.txt @@ -20,6 +20,7 @@ add_subdirectory(time) add_subdirectory(stdBase) add_subdirectory(usage) add_subdirectory(report) +add_subdirectory(memory) add_subdirectory(notification) option(BASE_RUN_TESTS "If ON, the tests will be run." OFF) diff --git a/src/utility/json/json_parser.h b/src/utility/json/json_parser.h index 70e701dacdc70ed560c9fa9311e3f903711b463b..91b5570eeb29366bae0fc5c9dbb4802b2c3e7967 100644 --- a/src/utility/json/json_parser.h +++ b/src/utility/json/json_parser.h @@ -46,7 +46,7 @@ namespace ieda { -static nlohmann::json getJsonData(nlohmann::json value, std::vector flag_list) +static nlohmann::json getJsonData(nlohmann::json value, std::vector flag_list, nlohmann::json default_value = "") { if (flag_list.empty()) { std::cout << "[json error] : The flag list is empty!" << std::endl; @@ -69,8 +69,8 @@ static nlohmann::json getJsonData(nlohmann::json value, std::vector key += "."; } } - std::cout << "[json error] : The configuration file key = " << key << " do not exist." << std::endl; - return value; + // std::cout << "[json error] : The configuration file key = " << key << " do not exist." << std::endl; + return default_value; } template diff --git a/src/utility/log/CMakeLists.txt b/src/utility/log/CMakeLists.txt index ce40213dee52a4c23946a00adca56ceb1b75ec88..fb7df2f39637501a5ad140a41461167d0b32a124 100644 --- a/src/utility/log/CMakeLists.txt +++ b/src/utility/log/CMakeLists.txt @@ -19,3 +19,8 @@ else() endif() TARGET_LINK_LIBRARIES(log PUBLIC ${LINK_glog} ${LINK_gflags} ${LINK_unwind}) + +target_include_directories(log + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/src/utility/log/Log.cc b/src/utility/log/Log.cc index b4ea89149766ee6d9667909edfa5c4053b385b0b..f7b0655176e782693c82b515b47c29817f802d3e 100644 --- a/src/utility/log/Log.cc +++ b/src/utility/log/Log.cc @@ -33,6 +33,7 @@ using std::string; + namespace ieda { bool Log::_is_init = false; @@ -59,13 +60,13 @@ void SignalHandle(const char* data, int size) */ void Log::init(char* argv[], std::string log_dir) { + std::filesystem::create_directories(log_dir.c_str()); // Check if glog is already initialized if (isInit()) { - LOG_WARNING << "Google logging is already initialized, skipping re-initialization."; - return; + LOG_WARNING << "Google logging is already initialized, re-initialization to log dir: " << log_dir; + end(); } - /*init google logging.*/ google::InitGoogleLogging(argv[0]); diff --git a/src/utility/log/Log.hh b/src/utility/log/Log.hh index ec56defa3eb9d1ce939cebe30f78143b26b6c150..517f57b10ff3d3725293c8e0e42876267872b4ae 100644 --- a/src/utility/log/Log.hh +++ b/src/utility/log/Log.hh @@ -36,6 +36,9 @@ namespace ieda { * from glog. * */ + + + class Log { enum class LogServerity : int diff --git a/src/utility/memory/CMakeLists.txt b/src/utility/memory/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f572845f595de30d8f8fad80cc3ed2e38bcb3024 --- /dev/null +++ b/src/utility/memory/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.11) +SET (CMAKE_CXX_STANDARD 20) + +AUX_SOURCE_DIRECTORY(./ SRC) +if(BUILD_STATIC_LIB) + ADD_LIBRARY(memory ${SRC}) +else() + ADD_LIBRARY(memory SHARED ${SRC}) +endif() +target_include_directories(memory + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/src/utility/memory/MemoryMonitor.cc b/src/utility/memory/MemoryMonitor.cc new file mode 100644 index 0000000000000000000000000000000000000000..b1a83fc6902d61471d85b7a5b02cf7dabc69575d --- /dev/null +++ b/src/utility/memory/MemoryMonitor.cc @@ -0,0 +1,138 @@ +#include "MemoryMonitor.hh" +#include +#include +#include +#include +#include +#include + +// 初始化静态成员 +std::mutex MemoryMonitor::file_mutex_; + +MemoryMonitor::MemoryMonitor(const std::string& label, const std::string& logFile) + : label_(label), logFile_(logFile) { + + start_memory_ = getCurrentRSS(); + start_vm_ = getCurrentVirtual(); + start_time_ = std::chrono::high_resolution_clock::now(); + + // 打开日志文件(追加模式) + std::lock_guard lock(file_mutex_); + std::ofstream log(logFile_, std::ios::app); + if (log.is_open()) { + log << getTimeStamp() << " [START] " << label_ + << " - Initial RSS: " << formatMemory(start_memory_) + << ", VM: " << formatMemory(start_vm_) << std::endl; + log.close(); + } +} + +MemoryMonitor::~MemoryMonitor() { + report(); +} + +void MemoryMonitor::report() { + size_t current_memory = getCurrentRSS(); + size_t current_vm = getCurrentVirtual(); + auto end_time = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(end_time - start_time_).count(); + + std::lock_guard lock(file_mutex_); + std::ofstream log(logFile_, std::ios::app); + if (log.is_open()) { + log << getTimeStamp() << " [REPORT] " << label_ << ":" << std::endl; + log << " Duration: " << duration << " ms" << std::endl; + log << " RSS Memory before: " << formatMemory(start_memory_) << std::endl; + log << " RSS Memory after: " << formatMemory(current_memory) << std::endl; + log << " RSS Memory change: " << formatMemory(current_memory - start_memory_) + << " (" << (current_memory > start_memory_ ? "+" : "") + << std::fixed << std::setprecision(2) + << (current_memory > start_memory_ ? + ((double)(current_memory - start_memory_) / start_memory_ * 100) : + ((double)(start_memory_ - current_memory) / start_memory_ * 100)) + << "%)" << std::endl; + + log << " Virtual Memory before: " << formatMemory(start_vm_) << std::endl; + log << " Virtual Memory after: " << formatMemory(current_vm) << std::endl; + log << " Virtual Memory change: " << formatMemory(current_vm - start_vm_) + << " (" << (current_vm > start_vm_ ? "+" : "") + << std::fixed << std::setprecision(2) + << (current_vm > start_vm_ ? + ((double)(current_vm - start_vm_) / start_vm_ * 100) : + ((double)(start_vm_ - current_vm) / start_vm_ * 100)) + << "%)" << std::endl; + + log << " Peak RSS Memory: " << formatMemory(getPeakRSS()) << std::endl; + log << std::endl; + log.close(); + } +} + +std::string MemoryMonitor::getTimeStamp() { + auto now = std::chrono::system_clock::now(); + auto time_t_now = std::chrono::system_clock::to_time_t(now); + auto ms = std::chrono::duration_cast( + now.time_since_epoch()) % 1000; + + std::stringstream ss; + ss << std::put_time(std::localtime(&time_t_now), "%Y-%m-%d %H:%M:%S"); + ss << '.' << std::setfill('0') << std::setw(3) << ms.count(); + return ss.str(); +} + +size_t MemoryMonitor::getCurrentRSS() { + std::ifstream statm("/proc/self/statm"); + long rss = 0; + if (statm.is_open()) { + long vm = 0; + statm >> vm >> rss; + statm.close(); + } + return rss * sysconf(_SC_PAGESIZE); // 转换页数为字节数 +} + +size_t MemoryMonitor::getCurrentVirtual() { + std::ifstream statm("/proc/self/statm"); + long vm = 0; + if (statm.is_open()) { + statm >> vm; + statm.close(); + } + return vm * sysconf(_SC_PAGESIZE); // 转换页数为字节数 +} + +size_t MemoryMonitor::getPeakRSS() { + std::ifstream status("/proc/self/status"); + std::string line; + size_t peak_rss = 0; + + if (status.is_open()) { + while (std::getline(status, line)) { + if (line.compare(0, 10, "VmHWM:") == 0) { + std::istringstream iss(line.substr(10)); + size_t kb; + iss >> kb; + peak_rss = kb * 1024; // 转换KB为字节 + break; + } + } + status.close(); + } + return peak_rss; +} + +std::string MemoryMonitor::formatMemory(size_t bytes) { + const char* units[] = {"B", "KB", "MB", "GB", "TB"}; + int unit = 0; + double size = static_cast(bytes); + + while (size >= 1024 && unit < 4) { + size /= 1024; + unit++; + } + + std::stringstream ss; + ss << std::fixed << std::setprecision(2) << size << " " << units[unit] + << " (" << bytes << " bytes)"; + return ss.str(); +} diff --git a/src/utility/memory/MemoryMonitor.hh b/src/utility/memory/MemoryMonitor.hh new file mode 100644 index 0000000000000000000000000000000000000000..4be55c72e4536c6725c3484c4eac00ddcb7aa727 --- /dev/null +++ b/src/utility/memory/MemoryMonitor.hh @@ -0,0 +1,43 @@ +#ifndef MEMORY_MONITOR_H +#define MEMORY_MONITOR_H + +#include +#include +#include + +class MemoryMonitor { +public: + // 构造函数:指定标签和输出文件名 + MemoryMonitor(const std::string& label, const std::string& logFile = "memory_monitor.log"); + + // 析构函数:自动报告内存使用情况 + ~MemoryMonitor(); + + // 手动报告内存使用情况 + void report(); + + // 获取当前时间戳 + static std::string getTimeStamp(); + +private: + // 获取当前进程的物理内存使用量(RSS),单位为字节 + size_t getCurrentRSS(); + + // 获取当前进程的虚拟内存使用量,单位为字节 + size_t getCurrentVirtual(); + + // 获取进程的峰值物理内存使用量 + size_t getPeakRSS(); + + // 格式化内存大小显示 + std::string formatMemory(size_t bytes); + + std::string label_; + std::string logFile_; + size_t start_memory_; + size_t start_vm_; + std::chrono::high_resolution_clock::time_point start_time_; + static std::mutex file_mutex_; // 保证多线程安全 +}; + +#endif // MEMORY_MONITOR_H diff --git a/src/utility/notification/CMakeLists.txt b/src/utility/notification/CMakeLists.txt index 2a6d6faed785c7bee908bd6087c61cf92de12e12..f47dbe2472bcf7ef0a6a4c46006121b5ec5fa4e2 100644 --- a/src/utility/notification/CMakeLists.txt +++ b/src/utility/notification/CMakeLists.txt @@ -7,22 +7,13 @@ pkg_check_modules(CURL REQUIRED libcurl) aux_source_directory(./ SRC) -if(BUILD_STATIC_LIB) - add_library(notification STATIC ${SRC}) -else() - add_library(notification SHARED ${SRC}) -endif() - -target_link_libraries(notification - PUBLIC - ${CURL_LIBRARIES} -) +add_library(notification STATIC ${SRC}) +target_link_libraries(notification PRIVATE curl) target_include_directories(notification PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CURL_INCLUDE_DIRS} ${HOME_THIRDPARTY}/json ) - -target_compile_options(notification PRIVATE ${CURL_CFLAGS_OTHER}) diff --git a/src/utility/notification/NotificationUtility.cpp b/src/utility/notification/NotificationUtility.cpp index 9a1dccbaa749dace16516f7f96e86d0760698c97..8c426c6bbd6d1e49a8090a6e0ce2e10bc33a63e3 100644 --- a/src/utility/notification/NotificationUtility.cpp +++ b/src/utility/notification/NotificationUtility.cpp @@ -17,13 +17,15 @@ #include "NotificationUtility.h" #include -#include +#include #include #include #include #include #include #include +#include +#include using json = nlohmann::json; @@ -33,12 +35,7 @@ namespace ieda { std::unique_ptr NotificationUtility::_instance = nullptr; std::mutex NotificationUtility::_instance_mutex; -// Callback function for libcurl to write response data -static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* userp) { - size_t total_size = size * nmemb; - userp->append(static_cast(contents), total_size); - return total_size; -} + NotificationUtility& NotificationUtility::getInstance() { std::lock_guard lock(_instance_mutex); @@ -91,20 +88,77 @@ bool NotificationUtility::initialize(const NotificationConfig& config) { bool NotificationUtility::initialize(const std::string& endpoint_url) { NotificationConfig config; - + bool is_env_set = true; + // Use provided URL or try to get from environment if (!endpoint_url.empty()) { config.endpoint_url = endpoint_url; } else { - const char* env_url = std::getenv("IEDA_NOTIFICATION_URL"); + const char* env_url = std::getenv("IEDA_ECOS_NOTIFICATION_URL"); if (env_url) { config.endpoint_url = env_url; + } else { + std::cerr << "IEDA_ECOS_NOTIFICATION_URL is not set" << std::endl; + is_env_set = false; } } - + + // Try to load task context from environment variables + const char* env_task_id = std::getenv("ECOS_TASK_ID"); + const char* env_project_id = std::getenv("ECOS_PROJECT_ID"); + const char* env_task_type = std::getenv("ECOS_TASK_TYPE"); + + if (env_project_id) + config.project_id = env_project_id; + else { + std::cerr << "ECOS_PROJECT_ID is not set" << std::endl; + is_env_set = false; + } + if (env_task_id) + config.task_id = env_task_id; + else { + std::cerr << "ECOS_TASK_ID is not set" << std::endl; + is_env_set = false; + } + if (env_task_type) + config.task_type = env_task_type; + else { + std::cerr << "ECOS_TASK_TYPE is not set" << std::endl; + is_env_set = false; + } + + if (!is_env_set) { + std::cerr << "Required environment variables for ECOS notifications are not set. Disabling notifications for this session." << std::endl; + setEnabled(false); + return false; + } + return initialize(config); } +bool NotificationUtility::initialize(const std::string& endpoint_url, + const std::string& task_id, + const std::string& project_id, + const std::string& task_type) { + NotificationConfig config; + config.endpoint_url = endpoint_url; + config.task_id = task_id; + config.project_id = project_id; + config.task_type = task_type; + + return initialize(config); +} + +NotificationUtility::HttpResponse NotificationUtility::sendNotification(const std::string& tool_name, + const std::map& metadata) { + NotificationPayload payload; + payload.tool_name = tool_name; + payload.metadata = metadata; + payload.timestamp = getCurrentTimestamp(); + + return sendNotification(payload); +} + NotificationUtility::HttpResponse NotificationUtility::sendNotification(const NotificationPayload& payload) { if (!isEnabled() || !isInitialized()) { HttpResponse response; @@ -132,31 +186,12 @@ NotificationUtility::HttpResponse NotificationUtility::sendNotification(const No HttpResponse response; response.success = true; - response.response_body = "Async notification queued"; return response; } else { return performHttpRequest(payload_json); } } -NotificationUtility::HttpResponse NotificationUtility::sendIterationNotification( - const std::string& algorithm_name, - int iteration, - int total_iterations, - const std::string& status, - const std::map& metrics) { - - NotificationPayload payload; - payload.algorithm_name = algorithm_name; - payload.stage = "iteration"; - payload.iteration_number = iteration; - payload.total_iterations = total_iterations; - payload.status = status; - payload.metrics = metrics; - payload.timestamp = getCurrentTimestamp(); - - return sendNotification(payload); -} bool NotificationUtility::isInitialized() const { std::lock_guard lock(_config_mutex); @@ -219,12 +254,21 @@ NotificationUtility::HttpResponse NotificationUtility::performHttpRequest(const return response; } - std::string response_body; struct curl_slist* headers = nullptr; try { + // Build URL with query parameters for task context + std::string url = _config.endpoint_url; + if (!_config.task_id.empty() && !_config.project_id.empty()) { + char separator = (url.find('?') != std::string::npos) ? '&' : '?'; + url = _config.endpoint_url + separator + "task_id=" + _config.task_id + "&project_id=" + _config.project_id; + if (!_config.task_type.empty()) { + url += "&task_type=" + _config.task_type; + } + } + // Set URL - curl_easy_setopt(curl, CURLOPT_URL, _config.endpoint_url.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // Set POST method curl_easy_setopt(curl, CURLOPT_POST, 1L); @@ -244,10 +288,6 @@ NotificationUtility::HttpResponse NotificationUtility::performHttpRequest(const curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - // Set response callback - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body); - // Set timeout curl_easy_setopt(curl, CURLOPT_TIMEOUT, _config.timeout_seconds); @@ -270,7 +310,6 @@ NotificationUtility::HttpResponse NotificationUtility::performHttpRequest(const if (res == CURLE_OK) { curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response.response_code); - response.response_body = response_body; response.success = (response.response_code >= 200 && response.response_code < 300); if (!response.success) { @@ -296,32 +335,52 @@ NotificationUtility::HttpResponse NotificationUtility::performHttpRequest(const std::string NotificationUtility::payloadToJson(const NotificationPayload& payload) { json j; - j["algorithm_name"] = payload.algorithm_name; - j["stage"] = payload.stage; - j["iteration_number"] = payload.iteration_number; - j["total_iterations"] = payload.total_iterations; - j["status"] = payload.status; + j["tool_name"] = payload.tool_name; j["timestamp"] = payload.timestamp; - // Add metrics - if (!payload.metrics.empty()) { - j["metrics"] = payload.metrics; - } - // Add metadata if (!payload.metadata.empty()) { - j["metadata"] = payload.metadata; - } - - // Add progress percentage - if (payload.total_iterations > 0) { - double progress = static_cast(payload.iteration_number) / payload.total_iterations * 100.0; - j["progress_percentage"] = progress; + json metadata_json; + for (const auto& [key, value] : payload.metadata) { + metadata_json[key] = convertAnyToJson(value); + } + j["metadata"] = metadata_json; } return j.dump(); } +nlohmann::json NotificationUtility::convertAnyToJson(const std::any& any_value) { + try { + // Try common types first + if (any_value.type() == typeid(std::string)) { + return std::any_cast(any_value); + } else if (any_value.type() == typeid(int)) { + return std::any_cast(any_value); + } else if (any_value.type() == typeid(int32_t)) { + return std::any_cast(any_value); + } else if (any_value.type() == typeid(int64_t)) { + return std::any_cast(any_value); + } else if (any_value.type() == typeid(double)) { + return std::any_cast(any_value); + } else if (any_value.type() == typeid(float)) { + return std::any_cast(any_value); + } else if (any_value.type() == typeid(bool)) { + return std::any_cast(any_value); + } else if (any_value.type() == typeid(const char*)) { + return std::string(std::any_cast(any_value)); + } else if (any_value.type() == typeid(std::map)) { + return std::any_cast>(any_value); + } else { + // For unknown types, try to convert to string representation + return std::string("unsupported_type:") + any_value.type().name(); + } + } catch (const std::bad_any_cast& e) { + // If conversion fails, return error info + return std::string("conversion_error:") + e.what(); + } +} + std::string NotificationUtility::getCurrentTimestamp() { auto now = std::chrono::system_clock::now(); auto time_t = std::chrono::system_clock::to_time_t(now); @@ -336,7 +395,7 @@ std::string NotificationUtility::getCurrentTimestamp() { } std::string NotificationUtility::loadAuthTokenFromEnv() { - const char* token = std::getenv("ID_SECRET"); + const char* token = std::getenv("IEDA_ECOS_NOTIFICATION_SECRET"); return token ? std::string(token) : std::string(); } @@ -355,4 +414,18 @@ void NotificationUtility::asyncNotificationWorker(const std::string& payload_jso } } +void NotificationUtility::setTaskContext(const std::string& task_id, + const std::string& project_id, + const std::string& task_type) { + std::lock_guard lock(_config_mutex); + _config.task_id = task_id; + _config.project_id = project_id; + _config.task_type = task_type; +} + +std::tuple NotificationUtility::getTaskContext() const { + std::lock_guard lock(_config_mutex); + return std::make_tuple(_config.task_id, _config.project_id, _config.task_type); +} + } // namespace ieda diff --git a/src/utility/notification/NotificationUtility.h b/src/utility/notification/NotificationUtility.h index cb916b4ad01e92f30a4c2afac5e29744360a03fa..2f79b0df7ecef9a931fea463fa9f174e4139eb7c 100644 --- a/src/utility/notification/NotificationUtility.h +++ b/src/utility/notification/NotificationUtility.h @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include namespace ieda { @@ -39,10 +42,9 @@ public: */ struct HttpResponse { long response_code; - std::string response_body; std::string error_message; bool success; - + HttpResponse() : response_code(0), success(false) {} }; @@ -51,14 +53,17 @@ public: */ struct NotificationConfig { std::string endpoint_url; // Target URL for notifications - std::string auth_token; // Authentication token (from ID_SECRET env var) + std::string auth_token; // Authentication token (from IEDA_ECOS_NOTIFICATION_SECRET env var) std::string content_type; // Content-Type header (default: application/json) int timeout_seconds; // Request timeout in seconds int max_retries; // Maximum number of retry attempts bool enable_ssl_verification; // Enable SSL certificate verification bool async_mode; // Send notifications asynchronously - - NotificationConfig() + std::string task_id; // Task ID for cloud integration + std::string project_id; // Project ID for cloud integration + std::string task_type; // Task type for cloud integration + + NotificationConfig() : content_type("application/json") , timeout_seconds(30) , max_retries(3) @@ -67,19 +72,15 @@ public: }; /** - * @brief Notification payload data structure + * @brief Generic notification payload data structure */ struct NotificationPayload { - std::string algorithm_name; // Name of the algorithm (e.g., "DetailedRouter") - std::string stage; // Current stage/phase - int iteration_number; // Current iteration number - int total_iterations; // Total number of iterations - std::string status; // Status: "running", "completed", "failed" - std::map metrics; // Custom metrics (e.g., violations, timing) - std::map metadata; // Additional metadata + std::string tool_name; // Name of the tool/algorithm + std::map metadata; // Generic metadata map std::string timestamp; // ISO 8601 timestamp - NotificationPayload() : iteration_number(0), total_iterations(0), status("running") {} + NotificationPayload() = default; + }; public: @@ -108,6 +109,28 @@ public: */ bool initialize(const std::string& endpoint_url = ""); + /** + * @brief Initialize with task context for cloud integration + * @param endpoint_url Target URL for notifications + * @param task_id Task ID for cloud integration + * @param project_id Project ID for cloud integration + * @param task_type Task type for cloud integration + * @return true if initialization successful, false otherwise + */ + bool initialize(const std::string& endpoint_url, + const std::string& task_id, + const std::string& project_id, + const std::string& task_type = ""); + + /** + * @brief Send generic notification with tool name and metadata + * @param tool_name Name of the tool/algorithm + * @param metadata Optional metadata map + * @return HttpResponse containing result (for sync mode) or empty response (for async mode) + */ + HttpResponse sendNotification(const std::string& tool_name, + const std::map& metadata = {}); + /** * @brief Send notification with custom payload * @param payload Notification payload data @@ -115,22 +138,7 @@ public: */ HttpResponse sendNotification(const NotificationPayload& payload); - /** - * @brief Send notification for algorithm iteration - * @param algorithm_name Name of the algorithm - * @param iteration Current iteration number - * @param total_iterations Total number of iterations - * @param status Current status - * @param metrics Optional metrics map - * @return HttpResponse containing result - */ - HttpResponse sendIterationNotification( - const std::string& algorithm_name, - int iteration, - int total_iterations, - const std::string& status = "running", - const std::map& metrics = {} - ); + /** * @brief Check if notification utility is properly initialized @@ -169,6 +177,22 @@ public: */ bool waitForPendingNotifications(int timeout_ms = 0); + /** + * @brief Set task context for cloud integration + * @param task_id Task ID + * @param project_id Project ID + * @param task_type Task type (optional) + */ + void setTaskContext(const std::string& task_id, + const std::string& project_id, + const std::string& task_type = ""); + + /** + * @brief Get current task context + * @return Tuple of (task_id, project_id, task_type) + */ + std::tuple getTaskContext() const; + ~NotificationUtility(); private: @@ -210,6 +234,13 @@ private: */ void asyncNotificationWorker(const std::string& payload_json); + /** + * @brief Convert std::any to JSON-compatible value + * @param any_value The std::any value to convert + * @return JSON-compatible value + */ + nlohmann::json convertAnyToJson(const std::any& any_value); + private: static std::unique_ptr _instance; static std::mutex _instance_mutex; diff --git a/src/utility/notification/README.md b/src/utility/notification/README.md index 1b78f13213f6062a98b2be910300be76ac07bdec..4325c3ed9ee7631199e5498474e9a903422982af 100644 --- a/src/utility/notification/README.md +++ b/src/utility/notification/README.md @@ -16,8 +16,8 @@ The NotificationUtility provides a thread-safe way to send HTTP POST notificatio ### Environment Variables -- `IEDA_NOTIFICATION_URL`: Target endpoint URL for notifications -- `ID_SECRET`: Authentication token (used as Bearer token) +- `IEDA_ECOS_NOTIFICATION_URL`: Target endpoint URL for notifications +- `IEDA_ECOS_NOTIFICATION_SECRET`: Authentication token (used as Bearer token) ### Programmatic Configuration @@ -48,7 +48,7 @@ notifier.initialize(config); // Initialize with environment variables auto& notifier = ieda::NotificationUtility::getInstance(); -notifier.initialize(); // Uses IEDA_NOTIFICATION_URL and ID_SECRET env vars +notifier.initialize(); // Uses IEDA_ECOS_NOTIFICATION_URL and IEDA_ECOS_NOTIFICATION_SECRET env vars // Send iteration notification auto response = notifier.sendIterationNotification( @@ -251,10 +251,10 @@ if __name__ == '__main__': ### Common Issues 1. **"Failed to initialize libcurl"**: Ensure libcurl is properly installed -2. **"Endpoint URL is required"**: Set `IEDA_NOTIFICATION_URL` environment variable +2. **"Endpoint URL is required"**: Set `IEDA_ECOS_NOTIFICATION_URL` environment variable 3. **SSL verification errors**: Set `config.enable_ssl_verification = false` for self-signed certificates 4. **Timeout errors**: Increase `config.timeout_seconds` value -5. **Authentication failures**: Verify `ID_SECRET` environment variable is set correctly +5. **Authentication failures**: Verify `IEDA_ECOS_NOTIFICATION_SECRET` environment variable is set correctly ### Debug Mode @@ -266,8 +266,8 @@ Test your webhook endpoint using curl: ```bash curl -X POST \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer your-token" \ - -d '{"algorithm_name":"test","iteration_number":1,"total_iterations":1,"status":"completed"}' \ - https://your-webhook-endpoint.com/notifications + -H "Content-Type: application/json" \ + -H "Authorization: Bearer mysecret" \ + -d "{\"tool_name\":\"test_tool\", \"timestamp\": \"$(date -u +'%Y-%m-%dT%H:%M:%S.%6NZ')\",\"metadata\": {\"k\": \"v\", \"status\":\"completed\"}}" \ + http://0.0.0.0:8000/webhook/notify ``` diff --git a/src/utility/time/Time.cc b/src/utility/time/Time.cc index cc614c93b75e98cf88e7aa44ef4927dbda81f514..4f875f1d67bf9f4bcfe97791806cf3cdcb82bfa6 100644 --- a/src/utility/time/Time.cc +++ b/src/utility/time/Time.cc @@ -27,9 +27,6 @@ #include #include -#include "absl/time/civil_time.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" #include "string/Str.hh" namespace ieda { @@ -49,4 +46,10 @@ const char* Time::getNowWallTime() return Str::printf("%s", s.str().c_str()); } +// Initialize static members +absl::Time Time::_start_time = absl::UnixEpoch(); +absl::Time Time::_end_time = absl::UnixEpoch(); +Time::TimeMode Time::_time_mode = Time::kOneShot; +double Time::_accumulate_time = 0.0; + } // namespace ieda diff --git a/src/utility/time/Time.hh b/src/utility/time/Time.hh index 85f356136b63f8af411732b7f2b07025e588766e..b26fb0b3180a48262458783d26b4cd2728aacd16 100644 --- a/src/utility/time/Time.hh +++ b/src/utility/time/Time.hh @@ -23,16 +23,63 @@ */ #pragma once +#include "absl/time/civil_time.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" + namespace ieda { /** * @brief The utility class relate to the time. * */ -class Time -{ +class Time { public: + enum TimeMode { + kOneShot = 0, // start the timer + kAccumulate, // stop the timer + }; + /** + * @brief Get now wall time such as 2021-05-08T17:06:42. + * + * @return const char* + */ static const char* getNowWallTime(); + + /** + * @brief Start the timer + */ + static void start() { _start_time = absl::Now(); } + + /** + * @brief Stop the timer + */ + static void stop() { + _end_time = absl::Now(); + if (_time_mode == kAccumulate) { + _accumulate_time += absl::ToDoubleSeconds(_end_time - _start_time); + } + } + + static void set_time_mode(TimeMode mode) { _time_mode = mode; } + static TimeMode get_time_mode() { return _time_mode; } + + static void resetAccumulateTime() { _accumulate_time = 0; } + static double get_accumulate_time() { return _accumulate_time; } + + /** + * @brief Get the elapsed time in seconds + * + * @return double The elapsed time in seconds + */ + static double elapsedTime() { return absl::ToDoubleSeconds(_end_time - _start_time); } + + private: + static absl::Time _start_time; + static absl::Time _end_time; + + static TimeMode _time_mode; + static double _accumulate_time; }; } // namespace ieda \ No newline at end of file diff --git a/src/utility/usage/CMakeLists.txt b/src/utility/usage/CMakeLists.txt index 065aa3086e77ed57ebe351dd899bb5f406f26498..099991ae50f5fbd83b9bd082932c8cf39b85010c 100644 --- a/src/utility/usage/CMakeLists.txt +++ b/src/utility/usage/CMakeLists.txt @@ -7,3 +7,7 @@ if(BUILD_STATIC_LIB) else() ADD_LIBRARY(usage SHARED ${SRC}) endif() +target_include_directories(usage + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/src/vectorization/CMakeLists.txt b/src/vectorization/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..86b6fb69c8c897917ddb886ecd1427a02562e2f5 --- /dev/null +++ b/src/vectorization/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(api) +add_subdirectory(database) +add_subdirectory(src) \ No newline at end of file diff --git a/src/vectorization/api/CMakeLists.txt b/src/vectorization/api/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d1732884052edd3770d3fbf8b8d19ff0e40afe1e --- /dev/null +++ b/src/vectorization/api/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library(ivec_api + vec_api.cpp +) + +target_link_libraries(ivec_api + PUBLIC + vectorization + ivec_layout_db +) + +target_include_directories(ivec_api + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/src/vectorization/api/vec_api.cpp b/src/vectorization/api/vec_api.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f8aeec71d905f1ed5495f81d386dd62f28c2b427 --- /dev/null +++ b/src/vectorization/api/vec_api.cpp @@ -0,0 +1,69 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** + +#include "init_sta.hh" +#include "vec_api.h" +#include "vectorization.h" + +namespace ivec { + +bool VectorizationApi::buildVectorizationLayoutData(const std::string path) +{ + Vectorization vectorization; + + vectorization.buildLayoutData(path); + + return true; +} + +bool VectorizationApi::buildVectorizationGraphData(const std::string path) +{ + Vectorization vectorization; + + vectorization.buildGraphData(path); + + return true; +} + +std::map VectorizationApi::getGraph(std::string path) +{ + Vectorization vectorization; + + return vectorization.getGraph(path); +} + +bool VectorizationApi::buildVectorizationFeature(const std::string dir, int patch_row_step, int patch_col_step) +{ + Vectorization vectorization; + + vectorization.buildFeature(dir, patch_row_step, patch_col_step); + + return true; +} + +bool VectorizationApi::runVecSTA(const std::string dir) +{ + Vectorization vectorization; + + vectorization.buildLayoutData(dir); + vectorization.buildGraphDataWithoutSave(dir); + + vectorization.runVecSTA(dir); + + return true; +} +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/api/vec_api.h b/src/vectorization/api/vec_api.h new file mode 100644 index 0000000000000000000000000000000000000000..a57f7d6dc78ab5c9eaf37bc1a253b0325851d604 --- /dev/null +++ b/src/vectorization/api/vec_api.h @@ -0,0 +1,42 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "vec_net.h" + +namespace ivec { + +class VectorizationApi +{ + public: + VectorizationApi() {} + ~VectorizationApi() {} + + bool buildVectorizationLayoutData(const std::string path); + bool buildVectorizationGraphData(const std::string path); + bool buildVectorizationFeature(const std::string dir, int patch_row_step, int patch_col_step); + + // run the vectorization sta for get timing data. + bool runVecSTA(const std::string dir = "VEC_STA"); + + std::map getGraph(std::string path = ""); + + private: +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/database/CMakeLists.txt b/src/vectorization/database/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..19e79c5b1952003621287c6d0ca62ed526ef30b4 --- /dev/null +++ b/src/vectorization/database/CMakeLists.txt @@ -0,0 +1,18 @@ +add_library(ivec_db + vec_node.cpp + vec_net.cpp + vec_cell.cpp + vec_instance.cpp +) + +target_link_libraries(ivec_db + PUBLIC + log + ivec_util +) + +target_include_directories(ivec_db + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) +target_compile_features(ivec_db PUBLIC cxx_std_20) \ No newline at end of file diff --git a/src/vectorization/database/vec_cell.cpp b/src/vectorization/database/vec_cell.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c35bc4e6d7f646957d77208e75b00743780baac5 --- /dev/null +++ b/src/vectorization/database/vec_cell.cpp @@ -0,0 +1,52 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 29/7/2025 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "vec_cell.h" + +#include "Log.hh" + +namespace ivec { + +VecCell* VecCells::get_cell(int id) +{ + auto it = _cell_map.find(id); + if (it != _cell_map.end()) { + return &it->second; + } + + return nullptr; +} + +void VecCells::addCell(VecCell cell) +{ + if (get_cell(cell.id) == nullptr) { + auto [it, success] = _cell_map.insert(std::make_pair(cell.id, cell)); + } +} + +} // namespace ivec diff --git a/src/vectorization/database/vec_cell.h b/src/vectorization/database/vec_cell.h new file mode 100644 index 0000000000000000000000000000000000000000..fd51d9940016e805a381dbb3e6d5d8ab299ba1d2 --- /dev/null +++ b/src/vectorization/database/vec_cell.h @@ -0,0 +1,62 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 29/7/2025 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include + +namespace ivec { + +struct VecCell +{ + int id; + std::string name; + int width; + int height; +}; + +class VecCells +{ + public: + VecCells() {} + ~VecCells() {} + + // getter + std::map& get_cell_map() { return _cell_map; } + VecCell* get_cell(int id); + + // setter + void addCell(VecCell cell); + + // operator + + private: + std::map _cell_map; +}; + +} // namespace ivec diff --git a/src/vectorization/database/vec_instance.cpp b/src/vectorization/database/vec_instance.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a43b40870635c0eb0c3e56ac01f74ba4f23e2196 --- /dev/null +++ b/src/vectorization/database/vec_instance.cpp @@ -0,0 +1,52 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 29/7/2025 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "vec_instance.h" + +#include "Log.hh" + +namespace ivec { + +VecInstance* VecInstances::get_instance(int id) +{ + auto it = _instance_map.find(id); + if (it != _instance_map.end()) { + return &it->second; + } + + return nullptr; +} + +void VecInstances::addInstance(VecInstance inst) +{ + if (get_instance(inst.id) == nullptr) { + auto [it, success] = _instance_map.insert(std::make_pair(inst.id, inst)); + } +} + +} // namespace ivec diff --git a/src/vectorization/database/vec_instance.h b/src/vectorization/database/vec_instance.h new file mode 100644 index 0000000000000000000000000000000000000000..960ab7b4c4ecdb78f195d6b111a519aa203791d7 --- /dev/null +++ b/src/vectorization/database/vec_instance.h @@ -0,0 +1,72 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 29/7/2025 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +namespace ivec { + +struct VecInstance +{ + uint64_t id; + int cell_id; + std::string name; + int x; + int y; + int width; + int height; + int llx; + int lly; + int urx; + int ury; + std::string orient; + std::string status; +}; + +class VecInstances +{ + public: + VecInstances() {} + ~VecInstances() {} + + // getter + std::map& get_instance_map() { return _instance_map; } + VecInstance* get_instance(int id); + + // setter + void addInstance(VecInstance inst); + + // operator + + private: + std::map _instance_map; +}; + +} // namespace ivec diff --git a/src/vectorization/database/vec_net.cpp b/src/vectorization/database/vec_net.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc1c7ae008e9489301127ae45e3f85a74f309d4a --- /dev/null +++ b/src/vectorization/database/vec_net.cpp @@ -0,0 +1,111 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "vec_net.h" + +#include "Log.hh" + +namespace ivec { + +void VecNetWire::add_path(VecNode* node1, VecNode* node2) +{ + _paths.push_back(std::make_pair(node1, node2)); +} + +void VecNetWire::addPatch(int patch_id, int layer_id) +{ + _patchs[patch_id].insert(layer_id); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void VecNet::addWire(VecNetWire wire) +{ + _wires.push_back(wire); +} + +VecNetFeature* VecNet::get_feature(bool b_create) +{ + if (_feature == nullptr && b_create) { + _feature = new VecNetFeature; + } + return _feature; +} + +VecNetWire* VecNet::findWire(int64_t wire_id) +{ + auto result = std::find_if(_wires.begin(), _wires.end(), [wire_id](VecNetWire wire) { return wire.get_id() == wire_id; }); + if (result != _wires.end()) { + return &(*result); + } + + return nullptr; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +VecNet* VecGraph::get_net(int net_id) +{ + auto it = _net_map.find(net_id); + if (it != _net_map.end()) { + return &it->second; + } + + return nullptr; +} + +VecNet* VecGraph::addNet(int net_id) +{ + if (get_net(net_id) == nullptr) { + VecNet vec_net(net_id); + auto [it, success] = _net_map.insert(std::make_pair(net_id, vec_net)); + } + + return get_net(net_id); +} + +void VecGraph::add_net_wire(int net_id, VecNetWire wire) +{ + auto& [start, end] = wire.get_connected_nodes(); + if (start == nullptr || end == nullptr) { + LOG_INFO << "wire error"; + } + + auto it = _net_map.find(net_id); + if (it != _net_map.end()) { + it->second.addWire(wire); + } else { + VecNet vec_net(net_id); + vec_net.addWire(wire); + auto result = _net_map.insert(std::make_pair(net_id, vec_net)); + } +} + +} // namespace ivec diff --git a/src/vectorization/database/vec_net.h b/src/vectorization/database/vec_net.h new file mode 100644 index 0000000000000000000000000000000000000000..885e7fa6349b71bcee8c502de15a1df54b95c38a --- /dev/null +++ b/src/vectorization/database/vec_net.h @@ -0,0 +1,206 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include + +#include "vec_node.h" + +namespace ivec { + +struct VecNetWireFeature +{ + int wire_width = 0; + int wire_len = 0; + int drc_num = 0; + double R = 0.0; + double C = 0.0; + double power = 0.0; + double delay = 0.0; + double slew = 0.0; + double congestion = 0.0; + double wire_density = 0.0; + std::vector drc_type = {}; +}; + +struct VecNetFeature +{ + int llx = 0; + int lly = 0; + int urx = 0; + int ury = 0; + int wire_len = 0; + int via_num = 0; + int drc_num = 0; + double R = 0.0; + double C = 0.0; + double power = 0.0; + double delay = 0.0; + double slew = 0.0; + int fanout = 0; + int aspect_ratio = 0; + int64_t width = 0; + int64_t height = 0; + int64_t area = 0; + float l_ness = 0.0; + std::vector drc_type = {}; + int64_t volume = 0; + std::vector layer_ratio = {}; + int rsmt = 0; +}; + +static int64_t wire_id_index = 0; + +class VecNetWire +{ + public: + VecNetWire(VecNode* node1 = nullptr, VecNode* node2 = nullptr, int id = -1) + { + _node_pair = std::make_pair(node1, node2); + _id = id == -1 ? wire_id_index++ : id; + }; + ~VecNetWire() { _paths.clear(); } + + // getter + int64_t get_id() { return _id; } + std::pair& get_connected_nodes() { return _node_pair; } + std::vector>& get_paths() { return _paths; } + VecNetWireFeature* get_feature(bool b_create = false) { return &_feature; } + std::map>& get_patchs() { return _patchs; } + + // setter + void set_start(VecNode* node) { _node_pair.first = node; } + void set_end(VecNode* node) { _node_pair.second = node; } + + void add_path(VecNode* node1, VecNode* node2); + + // operator + void addPatch(int patch_id, int layer_id); + + private: + int64_t _id = -1; + std::pair _node_pair; + std::vector> _paths; + + VecNetWireFeature _feature; + + std::map> _patchs; +}; + +struct VecPin +{ + int pin_id = -1; + std::string pin_name = ""; + std::string instance_name = ""; + bool is_driver = false; +}; + +struct NetRoutingPoint +{ + int x; + int y; + int layer_id; +}; + +struct NetRoutingVertex +{ + size_t id; + bool is_pin; + bool is_driver_pin; + NetRoutingPoint point; +}; + +struct NetRoutingEdge +{ + size_t source_id; + size_t target_id; + + std::vector path; +}; + +struct NetRoutingGraph +{ + std::vector vertices; + std::vector edges; +}; + +class VecNet +{ + public: + VecNet(int net_id) : _net_id(net_id) {} + ~VecNet() {} + + // getter + int get_net_id() { return _net_id; } + std::vector& get_wires() { return _wires; } + std::vector& get_pin_ids() { return _pin_ids; } + VecNetFeature* get_feature(bool b_create = false); + std::map& get_pin_list() { return _pin_list; } + NetRoutingGraph get_routing_graph() { return _routing_graph; } + // setter + void set_net_id(int net_id) { _net_id = net_id; } + void set_routing_graph(const NetRoutingGraph& routing_graph) { _routing_graph = routing_graph; } + + // operator + void addWire(VecNetWire wire); + void clearWire() { _wires.clear(); } + void addPinId(int id) { _pin_ids.push_back(id); } + void addPin(int id, VecPin pin) { _pin_list.insert(std::make_pair(id, pin)); } + VecNetWire* findWire(int64_t wire_id); + + private: + int _net_id = -1; + std::vector _wires; + std::vector _pin_ids; + std::map _pin_list; + VecNetFeature* _feature = nullptr; + NetRoutingGraph _routing_graph; +}; + +class VecGraph +{ + public: + VecGraph() {} + ~VecGraph() {} + + // getter + std::map& get_net_map() { return _net_map; } + VecNet* get_net(int net_id); + + // setter + VecNet* addNet(int net_id); + void add_net_wire(int net_id, VecNetWire wire); + + // operator + + private: + std::map _net_map; +}; + +} // namespace ivec diff --git a/src/vectorization/database/vec_node.cpp b/src/vectorization/database/vec_node.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a50cb69e22e633901e7ace551f861ef7cea37720 --- /dev/null +++ b/src/vectorization/database/vec_node.cpp @@ -0,0 +1,112 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "vec_node.h" + +#include "Log.hh" +#include "vec_grid_info.h" + +namespace ivec { +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void VecNodeData::set_type(VecNodeTYpe type) +{ + _type = VecNodeTYpe((static_cast(_type)) | (static_cast(type))); +} + +bool VecNodeData::is_type(VecNodeTYpe type) +{ + return (static_cast(_type) & static_cast(type)) > 0 ? true : false; +} + +bool VecNodeData::is_connect_type(VecNodeConnectType type) +{ + return (static_cast(_connect_type) & static_cast(type)) > 0 ? true : false; +} + +void VecNodeData::set_connect_type(VecNodeConnectType type) +{ + _connect_type = VecNodeConnectType((static_cast(_connect_type)) | (static_cast(type))); +} + +void VecNodeData::set_pin_id(int32_t id) +{ + if (_pin_id == -1) { + _pin_id = id; + } else { + if (_pin_id != id) { + LOG_INFO << "_pin_id : " << _pin_id << "; id :" << id; + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +uint64_t VecNode::get_node_id() +{ + return (((uint64_t) _layer_id) * ((uint64_t) gridInfoInst.node_col_num) * ((uint64_t) gridInfoInst.node_row_num)) + + ((uint64_t) _row_id) * ((uint64_t) gridInfoInst.node_col_num) + ((uint64_t) _col_id); +} + +int64_t VecNode::get_x() +{ + return gridInfoInst.calculate_x(_col_id); +} + +int64_t VecNode::get_y() +{ + return gridInfoInst.calculate_y(_row_id); +} + +VecNodeData* VecNode::get_node_data(int net_id, bool b_create) +{ + // if (net_id == -1 && _data_map.size() > 0) { + // /// get first data + // return &_data_map.begin()->second; + // } + // auto it = _data_map.find(net_id); + // if (it != _data_map.end()) { + // return &it->second; + // } else { + // if (b_create) { + // VecNodeData data; + // data.set_net_id(net_id); + // addNodeData(data); + // } + // } + // return &_data_map.find(net_id)->second; + if (_node_data == nullptr && b_create) { + _node_data = new VecNodeData(); + } + + return _node_data; +} + +} // namespace ivec diff --git a/src/vectorization/database/vec_node.h b/src/vectorization/database/vec_node.h new file mode 100644 index 0000000000000000000000000000000000000000..03df0d5ece961b38b0659f4b969dc204f6c6d524 --- /dev/null +++ b/src/vectorization/database/vec_node.h @@ -0,0 +1,151 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + +namespace ivec { + +enum class VecNodeTYpe : uint8_t +{ + kNone = 0, + vec_pdn = 1, + vec_net = 2, + vec_pin = 4, + vec_io = 8, + vec_obs = 16, + vec_instance = 32, + kMax +}; + +enum class VecNodeConnectType : uint8_t +{ + kNone = 0, + vec_wire = 1, + vec_delta = 2, + vec_via = 4, + vec_enclosure = 8, + kMax +}; + +struct VecNodeFeature +{ + std::set drc_ids; +}; + +class VecNodeData +{ + public: + VecNodeData() {} + ~VecNodeData() {} + + // getter + int32_t get_net_id() { return _net_id; } + int32_t get_pdn_id() { return _pdn_id; } + int32_t get_pin_id() { return _pin_id; } + int32_t get_instance_id() { return _inst_id; } + VecNodeTYpe get_type() { return _type; } + VecNodeConnectType get_connect_type() { return _connect_type; } + VecNodeFeature& get_feature() { return _feature; } + bool is_connect_type(VecNodeConnectType type); + bool is_wire() { return is_connect_type(VecNodeConnectType::vec_wire); } + bool is_delta() { return is_connect_type(VecNodeConnectType::vec_delta); } + bool is_via() { return is_connect_type(VecNodeConnectType::vec_via); } + bool is_enclosure() { return is_connect_type(VecNodeConnectType::vec_enclosure); } + + bool is_type(VecNodeTYpe type); + bool is_net() { return is_type(VecNodeTYpe::vec_net); } + bool is_pdn() { return is_type(VecNodeTYpe::vec_pdn); } + bool is_pin() { return is_type(VecNodeTYpe::vec_pin); } + bool is_io() { return is_type(VecNodeTYpe::vec_io); } + bool is_obs() { return is_type(VecNodeTYpe::vec_obs); } + + // setter + void set_net_id(int32_t id) { _net_id = id; } + void set_pdn_id(int32_t id) { _pdn_id = id; } + void set_pin_id(int32_t id); + void set_instance_id(int32_t id) { _inst_id = id; } + void set_type(VecNodeTYpe type); + void set_connect_type(VecNodeConnectType type); + + // operator + + private: + int32_t _net_id = -1; + int32_t _pdn_id = -1; + int32_t _pin_id = -1; + int32_t _inst_id = -1; + VecNodeTYpe _type = VecNodeTYpe::kNone; /// multiple type in one node + VecNodeConnectType _connect_type = VecNodeConnectType::kNone; + VecNodeFeature _feature; +}; + +class VecNode +{ + public: + VecNode() {} + ~VecNode() {} + + // getter + uint64_t get_node_id(); + int64_t get_x(); + int64_t get_y(); + int64_t get_row_id() { return _row_id; } + int64_t get_col_id() { return _col_id; } + int16_t get_layer_id() { return _layer_id; } + int32_t get_realx() { return _real_x; } + int32_t get_realy() { return _real_y; } + + VecNodeData* get_node_data(int net_id = -1, bool b_create = false); + + // setter + void set_row_id(int64_t row_id) { _row_id = row_id; } + void set_col_id(int64_t col_id) { _col_id = col_id; } + void set_layer_id(int16_t layer_id) { _layer_id = layer_id; } + void set_real_coordinate(int32_t real_x, int32_t real_y) + { + _real_x = real_x; + _real_y = real_y; + } + + // operator + + private: + int64_t _row_id = -1; // node order of layer rows + int64_t _col_id = -1; // node order of layer cols + int16_t _layer_id = -1; + VecNodeData* _node_data = nullptr; + int32_t _real_x = -1; + int32_t _real_y = -1; + // std::map _data_map; +}; + +} // namespace ivec diff --git a/src/vectorization/readme.dm b/src/vectorization/readme.dm new file mode 100644 index 0000000000000000000000000000000000000000..59648746dc4a4dc50cbd80539c93b3d20b6ef900 --- /dev/null +++ b/src/vectorization/readme.dm @@ -0,0 +1,2 @@ +#vectorization +vectorization is a data generation module that transforms design data from EDA data to vector data. \ No newline at end of file diff --git a/src/vectorization/src/CMakeLists.txt b/src/vectorization/src/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..de497477ef71b22eef8789c3194de0fe38ec2e3f --- /dev/null +++ b/src/vectorization/src/CMakeLists.txt @@ -0,0 +1,24 @@ +add_subdirectory(data_manager) +add_subdirectory(graph) +add_subdirectory(layout) +add_subdirectory(patch) +add_subdirectory(feature) +add_subdirectory(utility) + +add_library(vectorization +vectorization.cpp +) + +target_link_libraries(vectorization + PUBLIC + log + idm + ivec_dm + ivec_feature + memory +) + +target_include_directories(vectorization + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/src/vectorization/src/data_manager/CMakeLists.txt b/src/vectorization/src/data_manager/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ec014a77d48fb4bf303a1cd4c5627a26f56c793 --- /dev/null +++ b/src/vectorization/src/data_manager/CMakeLists.txt @@ -0,0 +1,19 @@ +add_library(ivec_dm + vec_dm.cpp + vec_file.cpp +) + +target_link_libraries(ivec_dm + PUBLIC + ivec_layout_dm + ivec_layout_db + ivec_graph_dm + ivec_patch_dm + ivec_patch_db + ivec_util +) + +target_include_directories(ivec_dm + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/src/vectorization/src/data_manager/vec_dm.cpp b/src/vectorization/src/data_manager/vec_dm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5adca9d84ffd8d86a55f605be3cf73980dcdd1a --- /dev/null +++ b/src/vectorization/src/data_manager/vec_dm.cpp @@ -0,0 +1,87 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** + +#include "vec_dm.h" + +#include "Log.hh" +#include "vec_file.h" +#include "vec_graph_check.hh" +#include "vec_graph_dm.h" +#include "vec_patch_dm.h" +#include "vec_wire_pattern.hh" + +namespace ivec { + +bool VecDataManager::buildLayoutData() +{ + return layout_dm.buildLayoutData(); +} + +bool VecDataManager::buildGraphData() +{ + VecGraphDataManager graph_dm(&layout_dm.get_layout()); + bool b_success = graph_dm.buildGraphData(); + + return b_success; +} + +bool VecDataManager::buildPatternData() +{ + VecWirePatternGenerator wire_pattern_gen; + wire_pattern_gen.genPatterns(); + wire_pattern_gen.patternSummary("/home/liweiguo/temp/file/pattern_summary.csv"); + return true; +} + +bool VecDataManager::buildPatchData(const std::string dir) +{ + patch_dm = new VecPatchDataManager(&layout_dm.get_layout()); + return patch_dm->buildPatchData(); +} + +bool VecDataManager::buildPatchData(const std::string dir, int patch_row_step, int patch_col_step) +{ + patch_dm = new VecPatchDataManager(&layout_dm.get_layout()); + return patch_dm->buildPatchData(patch_row_step, patch_col_step); +} + +bool VecDataManager::checkData() +{ + auto& graph = layout_dm.get_graph(); + + if (graph.size() > 0) { + // connectiviy check + VecLayoutChecker checker; + // checker.checkPinConnection(graph); + return checker.checkLayout(graph); + } + + return false; +} + +std::map VecDataManager::getGraph(std::string path) +{ + return layout_dm.get_graph(); +} + +void VecDataManager::saveData(const std::string dir) +{ + VecLayoutFileIO file_io(dir, &layout_dm.get_layout(), &patch_dm->get_patch_grid()); + file_io.saveJson(); +} + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/data_manager/vec_dm.h b/src/vectorization/src/data_manager/vec_dm.h new file mode 100644 index 0000000000000000000000000000000000000000..65341b822f5022de92ad6137b0120b7364d3502e --- /dev/null +++ b/src/vectorization/src/data_manager/vec_dm.h @@ -0,0 +1,53 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "vec_layout_dm.h" +#include "vec_net.h" +#include "vec_patch_dm.h" + +namespace ivec { + +class VecDataManager +{ + public: + VecDataManager() {} + ~VecDataManager() + { + if (patch_dm != nullptr) { + delete patch_dm; + patch_dm = nullptr; + } + } + + bool buildLayoutData(); + bool buildGraphData(); + bool buildPatternData(); + bool buildPatchData(const std::string dir); + bool buildPatchData(const std::string dir, int patch_row_step, int patch_col_step); + std::map getGraph(std::string path); + + bool checkData(); + void saveData(const std::string dir); + + public: + VecLayoutDataManager layout_dm; + VecPatchDataManager* patch_dm = nullptr; +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/data_manager/vec_file.cpp b/src/vectorization/src/data_manager/vec_file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b51811233b91ba85ceaf3f875b0cfb0febd52f0 --- /dev/null +++ b/src/vectorization/src/data_manager/vec_file.cpp @@ -0,0 +1,682 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** + +#include "vec_file.h" + +#include +#include +#include +#include +#include + +#include "Log.hh" +#include "idm.h" +#include "omp.h" +#include "usage.hh" +#include "vec_grid_info.h" + +namespace ivec { + +void VecLayoutFileIO::makeDir(std::string dir) +{ + namespace fs = std::filesystem; + if (false == fs::exists(dir) || false == fs::is_directory(dir)) { + fs::create_directories(dir); + } +} + +bool VecLayoutFileIO::saveJson() +{ + LOG_INFO << "Vectorization save json start... dir = " << _dir; + + makeDir(_dir); + + /// save cells + saveJsonCells(); + + /// save instances + saveJsonInstances(); + + /// save graph + saveJsonNets(); + + /// save patch + saveJsonPatchs(); + + LOG_INFO << "Vectorization save json end... dir = " << _dir; + + return true; +} + +bool VecLayoutFileIO::saveJsonNets() +{ + ieda::Stats stats; + LOG_INFO << "Vectorization save json net start..."; + makeDir(_dir + "/nets/"); + + auto& net_map = _layout->get_graph().get_net_map(); + const int BATCH_SIZE = 1500; // 可根据系统性能调整批量大小 + const int num_threads = omp_get_max_threads(); + const int NETS_PER_FILE = 1000; // 每个文件存储的net数量 + + // 预先将map的键值对复制到vector中,避免O(N^2)的迭代复杂度 + std::vector> net_vec; + net_vec.reserve(net_map.size()); + for (auto& [net_id, vec_net] : net_map) { + net_vec.emplace_back(net_id, &vec_net); + } + + // 计算需要的文件数量 + int num_files = (net_vec.size() + NETS_PER_FILE - 1) / NETS_PER_FILE; + + // 用于收集所有线程生成的JSON数据 + std::vector>> thread_batches(num_threads); + + int total = 0; +#pragma omp parallel + { + int thread_id = omp_get_thread_num(); + auto& local_batch = thread_batches[thread_id]; + local_batch.reserve(BATCH_SIZE + 100); // 预分配空间 + +#pragma omp for schedule(dynamic, 100) reduction(+ : total) + for (int i = 0; i < (int) net_vec.size(); ++i) { + // 直接O(1)访问vector元素,而不是O(i)的std::advance + const auto& [net_id, vec_net_ptr] = net_vec[i]; + auto& vec_net = *vec_net_ptr; + auto* idb_net = dmInst->get_idb_design()->get_net_list()->get_net_list()[net_id]; + + json json_net; + { + json_net["id"] = net_id; + json_net["name"] = idb_net->get_net_name(); + + /// net feature + { + json json_feature = {}; + auto net_feature = vec_net.get_feature(); + if (net_feature != nullptr) { + json_feature["llx"] = net_feature->llx; + json_feature["lly"] = net_feature->lly; + json_feature["urx"] = net_feature->urx; + json_feature["ury"] = net_feature->ury; + json_feature["wire_len"] = net_feature->wire_len; + json_feature["via_num"] = net_feature->via_num; + json_feature["drc_num"] = net_feature->drc_num; + json_feature["drc_type"] = net_feature->drc_type; + json_feature["R"] = net_feature->R; + json_feature["C"] = net_feature->C; + json_feature["power"] = net_feature->power; + json_feature["delay"] = net_feature->delay; + json_feature["slew"] = net_feature->slew; + json_feature["fanout"] = net_feature->fanout; + json_feature["aspect_ratio"] = net_feature->aspect_ratio; + json_feature["width"] = net_feature->width; + json_feature["height"] = net_feature->height; + json_feature["area"] = net_feature->area; + json_feature["volume"] = net_feature->volume; + json_feature["l_ness"] = net_feature->l_ness; + json_feature["layer_ratio"] = net_feature->layer_ratio; + json_feature["rsmt"] = net_feature->rsmt; + } + json_net["feature"] = json_feature; + } + + /// pins + { + json json_pins = json::array(); + auto& pin_list = vec_net.get_pin_list(); + + for (auto& [pin_id, vec_pin] : pin_list) { + json json_pin; + json_pin["id"] = pin_id; + json_pin["i"] = vec_pin.instance_name; + json_pin["p"] = vec_pin.pin_name; + json_pin["driver"] = vec_pin.is_driver ? 1 : 0; /// 1 : driver, 0 : load + json_pins.push_back(json_pin); + } + + json_net["pin_num"] = vec_net.get_pin_list().size(); + json_net["pins"] = json_pins; + } + + /// wires + auto& wires = vec_net.get_wires(); + json_net["wire_num"] = wires.size(); + total += wires.size(); + + json json_wires = json::array(); + + for (auto& wire : wires) { + json json_wire = {}; + { + json_wire["id"] = wire.get_id(); + + /// wire feature + { + json json_feature; + auto wire_feature = wire.get_feature(); + if (wire_feature != nullptr) { + json_feature["wire_width"] = wire_feature->wire_width; + json_feature["wire_len"] = wire_feature->wire_len; + json_feature["wire_density"] = wire_feature->wire_density; + json_feature["drc_num"] = wire_feature->drc_num; + json_feature["R"] = wire_feature->R; + json_feature["C"] = wire_feature->C; + json_feature["power"] = wire_feature->power; + json_feature["delay"] = wire_feature->delay; + json_feature["slew"] = wire_feature->slew; + json_feature["congestion"] = wire_feature->congestion; + json_feature["drc_type"] = wire_feature->drc_type; + } + json_wire["feature"] = json_feature; + } + + /// wire nodes + { + auto& [node1, node2] = wire.get_connected_nodes(); + auto json_node = makeNodePair(node1, node2); + json_wire["wire"] = json_node; + } + + /// paths + { + auto& paths = wire.get_paths(); + json_wire["path_num"] = paths.size(); + + json json_paths = json::array(); + + for (auto& [node1, node2] : paths) { + json json_node = makeNodePair(node1, node2); + json_paths.push_back(json_node); + } + + json_wire["paths"] = json_paths; + } + + /// patch id + { + auto& patches = wire.get_patchs(); + json_wire["patch_num"] = patches.size(); + + json json_patchs = json::array(); + + for (auto& [patch_id, layer_ids] : patches) { + json_patchs.push_back(patch_id); + } + + json_wire["patchs"] = json_patchs; + } + } + + json_wires.push_back(json_wire); + } + json_net["wires"] = json_wires; + + // routing graph + auto routing_graph = vec_net.get_routing_graph(); + json json_routing_graph = {}; + json json_routing_graph_vertices = json::array(); + json json_routing_graph_edges = json::array(); + std::ranges::for_each(routing_graph.vertices, [&](const NetRoutingVertex& vertex) { + json json_vertex; + json_vertex["id"] = vertex.id; + json_vertex["is_pin"] = vertex.is_pin ? 1 : 0; // 1: pin, 0: non-pin + json_vertex["is_driver_pin"] = vertex.is_driver_pin ? 1 : 0; // 1: driver pin, 0: load pin + json_vertex["x"] = vertex.point.x; + json_vertex["y"] = vertex.point.y; + json_vertex["layer_id"] = vertex.point.layer_id; + json_routing_graph_vertices.push_back(json_vertex); + }); + std::ranges::for_each(routing_graph.edges, [&](const NetRoutingEdge& edge) { + json json_edge; + json_edge["source_id"] = edge.source_id; + json_edge["target_id"] = edge.target_id; + json_edge["path"] = json::array(); + std::ranges::for_each(edge.path, [&](const NetRoutingPoint& point) { + json json_point; + json_point["x"] = point.x; + json_point["y"] = point.y; + json_point["layer_id"] = point.layer_id; + json_edge["path"].push_back(json_point); + }); + json_routing_graph_edges.push_back(json_edge); + }); + json_routing_graph["vertices"] = json_routing_graph_vertices; + json_routing_graph["edges"] = json_routing_graph_edges; + json_net["routing_graph"] = json_routing_graph; + } + + // 将结果添加到本地批次中,存储net_id和对应的json数据 + local_batch.emplace_back(net_id, std::move(json_net)); + + if (i % 1000 == 0) { +#pragma omp critical(log) + { + LOG_INFO << "Processing net : " << i << " / " << net_vec.size(); + } + } + } + } + + // 并行区域结束后,合并所有线程的结果 + LOG_INFO << "JSON generation completed, merging results..."; + + // 创建一个映射,将net_id映射到对应的json数据 + std::map all_nets; + for (const auto& batch : thread_batches) { + for (const auto& [net_id, json_data] : batch) { + all_nets[net_id] = json_data; + } + } + + // 批量写入文件 + LOG_INFO << "Starting batch file writing..."; + + // 计算需要写入的文件数量 + int total_files = (all_nets.size() + NETS_PER_FILE - 1) / NETS_PER_FILE; + +#pragma omp parallel for schedule(dynamic, 1) num_threads(std::min(num_threads, 8)) + for (int file_idx = 0; file_idx < total_files; ++file_idx) { + // 计算当前文件包含的网络范围 + int start_net_idx = file_idx * NETS_PER_FILE; + int end_net_idx = std::min((file_idx + 1) * NETS_PER_FILE - 1, (int) all_nets.size() - 1); + + // 创建文件名格式: net_START_END.json + std::string filename = "net_" + std::to_string(start_net_idx) + "_" + std::to_string(end_net_idx) + ".json"; + std::string full_path = _dir + "/nets/" + filename; + + // 创建一个包含当前批次网络的数组 + json batch_json = json::array(); + + // 找到这个范围内的所有网络 + auto it = all_nets.begin(); + std::advance(it, start_net_idx); + + for (int i = start_net_idx; i <= end_net_idx && it != all_nets.end(); ++i, ++it) { + batch_json.push_back(it->second); + } + + std::ofstream file_stream(full_path); + file_stream << batch_json; + file_stream.close(); + +#pragma omp critical(log) + { + LOG_INFO << "Writing files: " << (file_idx + 1) * NETS_PER_FILE << " / " << all_nets.size(); + } + } + + LOG_INFO << "Saved nets: " << all_nets.size() << " / " << net_vec.size(); + LOG_INFO << "Total wires: " << total; + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization save json net end..."; + + return true; +} + +bool VecLayoutFileIO::saveJsonPatchs() +{ + ieda::Stats stats; + LOG_INFO << "Vectorization save json patchs start..."; + makeDir(_dir + "/patchs/"); + + if (!_patch_grid) { + return false; + } + + auto& patchs = _patch_grid->get_patchs(); + const int BATCH_SIZE = 1500; // 可根据系统性能调整批量大小 + const int num_threads = omp_get_max_threads(); + const int PATCHS_PER_FILE = 1000; // 每个文件存储的patch数量 + + // 预先将map的键值对复制到vector中,避免O(N²)的迭代复杂度 + std::vector> patch_vec; + patch_vec.reserve(patchs.size()); + for (auto& [patch_id, patch] : patchs) { + patch_vec.emplace_back(patch_id, &patch); + } + + // 计算需要的文件数量 + int num_files = (patch_vec.size() + PATCHS_PER_FILE - 1) / PATCHS_PER_FILE; + + // 用于收集所有线程生成的JSON数据 + std::vector>> thread_batches(num_threads); + +#pragma omp parallel + { + int thread_id = omp_get_thread_num(); + auto& local_batch = thread_batches[thread_id]; + local_batch.reserve(BATCH_SIZE + 100); // 预分配空间 + +#pragma omp for schedule(dynamic, 100) + for (int i = 0; i < (int) patch_vec.size(); ++i) { + const auto& [patch_id, patch_ptr] = patch_vec[i]; + auto& patch = *patch_ptr; + + json json_patch; + { + auto [llx, lly] = gridInfoInst.get_node_coodinate(patch.rowIdMin, patch.colIdMin); + auto [urx, ury] = gridInfoInst.get_node_coodinate(patch.rowIdMax, patch.colIdMax); + int area = (urx - llx) * (ury - lly); + + json_patch["id"] = patch.patch_id; + json_patch["patch_id_row"] = patch.patch_id_row; + json_patch["patch_id_col"] = patch.patch_id_col; + json_patch["llx"] = llx; + json_patch["lly"] = lly; + json_patch["urx"] = urx; + json_patch["ury"] = ury; + json_patch["row_min"] = patch.rowIdMin; + json_patch["row_max"] = patch.rowIdMax; + json_patch["col_min"] = patch.colIdMin; + json_patch["col_max"] = patch.colIdMax; + json_patch["area"] = area; + json_patch["cell_density"] = patch.cell_density; + json_patch["pin_density"] = patch.pin_density; + json_patch["net_density"] = patch.net_density; + json_patch["macro_margin"] = patch.macro_margin; + json_patch["RUDY_congestion"] = patch.RUDY_congestion; + json_patch["EGR_congestion"] = patch.EGR_congestion; + json_patch["timing"] = patch.timing_map; + json_patch["power"] = patch.power_map; + json_patch["IR_drop"] = patch.ir_drop_map; + + json json_sub_nets = json::array(); + std::unordered_map unique_json_sub_nets; + + json json_layers = json::array(); + + std::vector> layer_vec; + layer_vec.reserve(patch.get_layer_map().size()); + for (auto& [layer_id, patch_layer] : patch.get_layer_map()) { + layer_vec.emplace_back(layer_id, &patch_layer); + } + + for (const auto& [layer_id, patch_layer_ptr] : layer_vec) { + auto& patch_layer = *patch_layer_ptr; + json json_layer = {}; + json_layer["id"] = layer_id; + // layer feature + { + json json_layer_feature; + + json_layer_feature["wire_width"] = patch_layer.wire_width; + json_layer_feature["wire_len"] = patch_layer.wire_len; + json_layer_feature["wire_density"] = (patch_layer.wire_width * patch_layer.wire_len) / static_cast(area); + json_layer_feature["congestion"] = patch_layer.congestion; + + json_layer["feature"] = json_layer_feature; + } + /// sub net in patch for each layer + auto& sub_nets = patch_layer.get_sub_nets(); + json_layer["net_num"] = sub_nets.size(); + + json json_nets = json::array(); + + std::vector> subnet_vec; + subnet_vec.reserve(sub_nets.size()); + for (auto& [net_id, vec_net] : sub_nets) { + subnet_vec.emplace_back(net_id, &vec_net); + } + + for (const auto& [net_id, vec_net_ptr] : subnet_vec) { + auto& vec_net = *vec_net_ptr; + json json_net = {}; + json_net["id"] = net_id; + + // subnet + auto* idb_net = dmInst->get_idb_design()->get_net_list()->get_net_list()[net_id]; + json json_sub_net; + json_sub_net["id"] = net_id; + json_sub_net["llx"] = std::max(idb_net->get_bounding_box()->get_low_x(), llx); + json_sub_net["lly"] = std::max(idb_net->get_bounding_box()->get_low_y(), lly); + json_sub_net["urx"] = std::min(idb_net->get_bounding_box()->get_high_x(), urx); + json_sub_net["ury"] = std::min(idb_net->get_bounding_box()->get_high_y(), ury); + unique_json_sub_nets[net_id] = json_sub_net; + + /// wires + auto& wires = vec_net.get_wires(); + json_net["wire_num"] = wires.size(); + + json json_wires = json::array(); + + for (auto& wire : wires) { + json json_wire = {}; + { + json_wire["id"] = wire.get_id(); + + /// wire feature + { + json json_feature; + auto wire_feature = wire.get_feature(); + if (wire_feature != nullptr) { + json_feature["wire_len"] = wire_feature->wire_len; + } + json_wire["feature"] = json_feature; + } + + /// paths + { + auto& paths = wire.get_paths(); + json_wire["path_num"] = paths.size(); + + json json_paths = json::array(); + + for (auto& [node1, node2] : paths) { + json json_node = makeNodePair(node1, node2); + json_paths.push_back(json_node); + } + + json_wire["paths"] = json_paths; + } + } + + json_wires.push_back(json_wire); + } + json_net["wires"] = json_wires; + json_nets.push_back(json_net); + } + json_layer["nets"] = json_nets; + + json_layers.push_back(json_layer); + } + + for (const auto& [net_id, json_sub_net] : unique_json_sub_nets) { + json_sub_nets.push_back(json_sub_net); + } + json_patch["sub_nets"] = json_sub_nets; + json_patch["patch_layer"] = json_layers; + } + + // 将结果添加到本地批次中,存储patch_id和对应的json数据 + local_batch.emplace_back(patch_id, std::move(json_patch)); + + if (i % 1000 == 0) { +#pragma omp critical(log) + { + LOG_INFO << "Processing patch : " << i << " / " << patch_vec.size(); + } + } + } + } + + // 并行区域结束后,合并所有线程的结果 + LOG_INFO << "JSON generation completed, merging results..."; + + // 创建一个映射,将patch_id映射到对应的json数据 + std::map all_patches; + for (const auto& batch : thread_batches) { + for (const auto& [patch_id, json_data] : batch) { + all_patches[patch_id] = json_data; + } + } + + // 批量写入文件 + LOG_INFO << "Starting batch file writing..."; + + // 计算需要写入的文件数量 + int total_files = (all_patches.size() + PATCHS_PER_FILE - 1) / PATCHS_PER_FILE; + +#pragma omp parallel for schedule(dynamic, 1) num_threads(std::min(num_threads, 8)) + for (int file_idx = 0; file_idx < total_files; ++file_idx) { + // 计算当前文件包含的patch范围 + int start_patch_idx = file_idx * PATCHS_PER_FILE; + int end_patch_idx = std::min((file_idx + 1) * PATCHS_PER_FILE - 1, (int) all_patches.size() - 1); + + // 创建文件名格式: patch_START_END.json + std::string filename = "patch_" + std::to_string(start_patch_idx) + "_" + std::to_string(end_patch_idx) + ".json"; + std::string full_path = _dir + "/patchs/" + filename; + + // 创建一个包含当前批次patch的数组 + json batch_json = json::array(); + + // 找到这个范围内的所有patch + auto it = all_patches.begin(); + std::advance(it, start_patch_idx); + + for (int i = start_patch_idx; i <= end_patch_idx && it != all_patches.end(); ++i, ++it) { + batch_json.push_back(it->second); + } + + std::ofstream file_stream(full_path); + file_stream << batch_json; + file_stream.close(); + +#pragma omp critical(log) + { + LOG_INFO << "Writing files: " << (file_idx + 1) * PATCHS_PER_FILE << " / " << all_patches.size(); + } + } + + LOG_INFO << "Saved patches: " << all_patches.size() << " / " << patch_vec.size(); + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization save json patchs end..."; + + return true; +} + +json VecLayoutFileIO::makeNodePair(VecNode* node1, VecNode* node2) +{ + json json_node; + + json_node["id1"] = node1->get_node_id(); + json_node["x1"] = node1->get_x(); + json_node["y1"] = node1->get_y(); + json_node["real_x1"] = node1->get_realx(); + json_node["real_y1"] = node1->get_realy(); + json_node["r1"] = node1->get_row_id(); /// row + json_node["c1"] = node1->get_col_id(); /// col + json_node["l1"] = node1->get_layer_id(); /// layer order + json_node["p1"] = node1->get_node_data()->get_pin_id(); /// pin + + json_node["id2"] = node2->get_node_id(); + json_node["x2"] = node2->get_x(); + json_node["y2"] = node2->get_y(); + json_node["real_x2"] = node2->get_realx(); + json_node["real_y2"] = node2->get_realy(); + json_node["r2"] = node2->get_row_id(); /// row + json_node["c2"] = node2->get_col_id(); /// col + json_node["l2"] = node2->get_layer_id(); /// layer order + json_node["p2"] = node2->get_node_data()->get_pin_id(); /// pin + return json_node; +} + +bool VecLayoutFileIO::saveJsonCells() +{ + ieda::Stats stats; + LOG_INFO << "Vectorization save json cells start..."; + makeDir(_dir + "/cells/"); + + json json_cells; + { + auto& cell_map = _layout->get_cells().get_cell_map(); + json_cells["cell_num"] = cell_map.size(); + + auto json_cell_list = json::array(); + for (auto& [id, vec_cell] : cell_map) { + json json_cell; + json_cell["id"] = vec_cell.id; + json_cell["name"] = vec_cell.name; + json_cell["width"] = vec_cell.width; + json_cell["height"] = vec_cell.height; + + json_cell_list.push_back(json_cell); + } + + json_cells["cells"] = json_cell_list; + } + + std::string filename = _dir + "/cells/cells.json"; + std::ofstream file_stream(filename); + file_stream << json_cells; + file_stream.close(); + + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization save json cells end..."; + + return true; +} + +bool VecLayoutFileIO::saveJsonInstances() +{ + ieda::Stats stats; + LOG_INFO << "Vectorization save json instances start..."; + makeDir(_dir + "/instances/"); + + json json_insts; + { + auto& inst_map = _layout->get_instances().get_instance_map(); + json_insts["instance_num"] = inst_map.size(); + + auto json_inst_list = json::array(); + for (auto& [id, vec_inst] : inst_map) { + json json_inst; + json_inst["id"] = vec_inst.id; + json_inst["cell_id"] = vec_inst.cell_id; + json_inst["name"] = vec_inst.name; + json_inst["x"] = vec_inst.x; + json_inst["y"] = vec_inst.y; + json_inst["width"] = vec_inst.width; + json_inst["height"] = vec_inst.height; + json_inst["llx"] = vec_inst.llx; + json_inst["lly"] = vec_inst.lly; + json_inst["urx"] = vec_inst.urx; + json_inst["ury"] = vec_inst.ury; + + json_inst_list.push_back(json_inst); + } + + json_insts["instances"] = json_inst_list; + } + + std::string filename = _dir + "/instances/instances.json"; + std::ofstream file_stream(filename); + file_stream << json_insts; + file_stream.close(); + + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization save json instances end..."; + + return true; +} + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/data_manager/vec_file.h b/src/vectorization/src/data_manager/vec_file.h new file mode 100644 index 0000000000000000000000000000000000000000..bba1d68b601c99cbcb4989328de79383e5f4f411 --- /dev/null +++ b/src/vectorization/src/data_manager/vec_file.h @@ -0,0 +1,57 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "json.hpp" +#include "vec_layout.h" +#include "vec_net.h" +#include "vec_node.h" +#include "vec_patch.h" +#include "vec_patch_grid.h" + +namespace ivec { +using json = nlohmann::ordered_json; + +class VecLayoutFileIO +{ + public: + VecLayoutFileIO(std::string dir, VecLayout* layout, VecPatchGrid* patch_grid = nullptr) + { + _dir = dir; + _layout = layout; + _patch_grid = patch_grid; + } + ~VecLayoutFileIO() {} + + bool saveJson(); + + private: + std::string _dir = ""; + VecLayout* _layout = nullptr; + VecPatchGrid* _patch_grid = nullptr; + + bool saveJsonNets(); + bool saveJsonPatchs(); + bool saveJsonCells(); + bool saveJsonInstances(); + + void makeDir(std::string dir); + json makeNodePair(VecNode* node1, VecNode* node2); +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/feature/CMakeLists.txt b/src/vectorization/src/feature/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..2634519fab045e76699b525d6cc14621c820f95f --- /dev/null +++ b/src/vectorization/src/feature/CMakeLists.txt @@ -0,0 +1,31 @@ +add_library(ivec_feature + vec_feature.cpp + vec_feature_drc.cpp + vec_feature_timing.cpp + vec_feature_statis.cpp +) + +target_link_libraries(ivec_feature + PUBLIC + ivec_layout_db + ivec_patch_db + ivec_patch_dm + idm + idb + log + usage + ivec_util + tool_api_idrc + eval_congestion_api + eval_density_api + eval_wirelength_api +) + +set(EVALUTION_INCLUDE ${HOME_EVALUATION}/src/util) + +target_include_directories(ivec_feature + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${EVALUTION_INCLUDE} + ${HOME_DATABASE}/interaction/RT_DRC +) \ No newline at end of file diff --git a/src/vectorization/src/feature/vec_feature.cpp b/src/vectorization/src/feature/vec_feature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f103e88f1e881a6568512a2e685da4c1655f68ca --- /dev/null +++ b/src/vectorization/src/feature/vec_feature.cpp @@ -0,0 +1,56 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** + +#include + +#include "Log.hh" +#include "idm.h" +#include "vec_feature.h" + +namespace ivec { + +void VecFeature::buildFeatureDrc(std::string drc_path) +{ + if (drc_path == "") { + drc_path = _dir + "/" + dmInst->get_idb_design()->get_design_name() + "_route_baseline_drc.json"; + } + + namespace fs = std::filesystem; + if (false == fs::exists(drc_path)) { + LOG_WARNING << "Drc file not exist, path : " << drc_path; + return; + } + + VecFeatureDrc feature_drc(_layout, drc_path); + + feature_drc.build(); +} + +void VecFeature::buildFeatureTiming() +{ + VecFeatureTiming feature_timing(_layout, _dir); + + feature_timing.build(); +} + +void VecFeature::buildFeatureStatis() +{ + VecFeatureStatis feature_statis(_layout, _patch_grid); + + feature_statis.build(); +} +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/feature/vec_feature.h b/src/vectorization/src/feature/vec_feature.h new file mode 100644 index 0000000000000000000000000000000000000000..412f9231cd430b9de051625a9a05ae058bef93c2 --- /dev/null +++ b/src/vectorization/src/feature/vec_feature.h @@ -0,0 +1,48 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "vec_feature_drc.h" +#include "vec_feature_statis.h" +#include "vec_feature_timing.h" +#include "vec_layout.h" + +namespace ivec { + +class VecFeature +{ + public: + VecFeature(VecLayout* layout, VecPatchGrid* patch_grid, std::string dir) + { + _layout = layout; + _patch_grid = patch_grid; + _dir = dir; /// feature directory + } + ~VecFeature() {} + + void buildFeatureDrc(std::string drc_path = ""); + void buildFeatureTiming(); + void buildFeatureStatis(); + + private: + VecLayout* _layout; + VecPatchGrid* _patch_grid; + std::string _dir; +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/feature/vec_feature_drc.cpp b/src/vectorization/src/feature/vec_feature_drc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6ff1a0ecf89983733f9b24459a12bb2fff02a72a --- /dev/null +++ b/src/vectorization/src/feature/vec_feature_drc.cpp @@ -0,0 +1,297 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** + +#include "vec_feature_drc.h" + +#include +#include +#include +#include +#include + +#include "IdbLayer.h" +#include "Log.hh" +#include "idrc_io.h" +#include "ids.hpp" +#include "omp.h" +#include "usage.hh" +#include "vec_grid_info.h" + +namespace ivec { + +void VecFeatureDrc::build() +{ + markNodes(); + + feature_graph(); + feature_patch(); +} + +void VecFeatureDrc::feature_graph() +{ + markWires(); + markNets(); +} + +void VecFeatureDrc::feature_patch() +{ +} + +void VecFeatureDrc::markNodes() +{ + ieda::Stats stats; + + LOG_INFO << "Vectorization mark nodes drc start..."; + + omp_lock_t lck; + omp_init_lock(&lck); + + auto& layout_layers = _layout->get_layout_layers(); + + auto detail_drc_map = iplf::drcInst->getDetailCheckResult(_drc_path); + int drc_id = 0; + int drc_without_net = 0; + + // 新增:用于记录 drc_id 和 drc_type(rule)的映射 + std::map drc_id_to_type; + + for (auto& [rule, drc_list_map] : detail_drc_map) { + for (auto& [layer_name, drc_spot_list] : drc_list_map) { +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < (int) drc_spot_list.size(); ++i) { + /// set to node if node data exist + auto& drc_spot = drc_spot_list[i]; + auto order = _layout->findLayerId(_layout->findLayerName(drc_spot.layer_idx)); + if (order < 0) { + continue; + } + + auto& grid = layout_layers.findLayoutLayer(order)->get_grid(); + + /// get row & col + bool b_find_net = false; + auto [row_1, row_2, co_1, col_2] + = gridInfoInst.get_node_id_range(drc_spot.ll_x - 1, drc_spot.ll_y + 1, drc_spot.ur_x - 1, drc_spot.ur_y + 1); + for (int row = row_1; row <= row_2; ++row) { + for (int col = co_1; col <= col_2; ++col) { + auto* node = grid.get_node(row, col); + if (node != nullptr && node->get_node_data() != nullptr) { + auto& node_feature = node->get_node_data()->get_feature(); + omp_set_lock(&lck); + node_feature.drc_ids.insert(drc_id + i); + drc_id_to_type[drc_id + i] = rule; // 将 drc_id 和 rule 关联 + omp_unset_lock(&lck); + + if (node->get_node_data()->get_net_id() >= 0) { + b_find_net = true; + } + } + } + } + + if (false == b_find_net) { + omp_set_lock(&lck); + drc_without_net++; + omp_unset_lock(&lck); + } + + drc_id += drc_spot_list.size(); + } + } + } + + LOG_INFO << "drc with no net id : " << drc_without_net; + + omp_destroy_lock(&lck); + + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization mark nodes drc end..."; + + _drc_id_to_type = std::move(drc_id_to_type); +} + +void VecFeatureDrc::markWires() +{ + ieda::Stats stats; + + omp_lock_t lck; + omp_init_lock(&lck); + + LOG_INFO << "Vectorization mark wire drc start..."; + + auto& layout_layers = _layout->get_layout_layers(); + + auto& net_map = _layout->get_graph().get_net_map(); +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < (int) net_map.size(); ++i) { + auto it = net_map.begin(); + std::advance(it, i); + auto& vec_net = it->second; + + // auto* net_feature = vec_net.get_feature(true); + for (auto& wire : vec_net.get_wires()) { + std::set drc_ids; + + auto* wire_feature = wire.get_feature(true); + + std::set node_list; + for (auto& [node1, node2] : wire.get_paths()) { + if (node1->get_layer_id() == node2->get_layer_id()) { + auto order = node1->get_layer_id(); + auto& grid = layout_layers.findLayoutLayer(order)->get_grid(); + + int min_row = std::min(node1->get_row_id(), node2->get_row_id()); + int max_row = std::max(node1->get_row_id(), node2->get_row_id()); + int min_col = std::min(node1->get_col_id(), node2->get_col_id()); + int max_col = std::max(node1->get_col_id(), node2->get_col_id()); + + for (int row = min_row; row <= max_row; ++row) { + for (int col = min_col; col <= max_col; ++col) { + auto* node = grid.get_node(row, col); + if (node == nullptr || node->get_node_data() == nullptr) { + continue; + } + + drc_ids.insert(node->get_node_data()->get_feature().drc_ids.begin(), node->get_node_data()->get_feature().drc_ids.end()); + } + } + + wire_feature->drc_num += drc_ids.size(); + // net_feature->drc_num += drc_ids.size(); + + omp_set_lock(&lck); + mark_drc_num += drc_ids.size(); + omp_unset_lock(&lck); + } else { + // 如果路径跨层,分别处理 node1 和 node2 的 drc_ids + drc_ids.insert(node1->get_node_data()->get_feature().drc_ids.begin(), node1->get_node_data()->get_feature().drc_ids.end()); + drc_ids.insert(node2->get_node_data()->get_feature().drc_ids.begin(), node2->get_node_data()->get_feature().drc_ids.end()); + + wire_feature->drc_num += node1->get_node_data()->get_feature().drc_ids.size(); + // net_feature->drc_num += node1->get_node_data()->get_feature().drc_ids.size(); + + wire_feature->drc_num += node2->get_node_data()->get_feature().drc_ids.size(); + // net_feature->drc_num += node2->get_node_data()->get_feature().drc_ids.size(); + + omp_set_lock(&lck); + mark_drc_num += node1->get_node_data()->get_feature().drc_ids.size(); + mark_drc_num += node2->get_node_data()->get_feature().drc_ids.size(); + omp_unset_lock(&lck); + } + } + // 填充 wire_feature->drc_type + for (auto drc_id : drc_ids) { + wire_feature->drc_type.push_back(_drc_id_to_type[drc_id]); // 根据 drc_id 获取对应的 drc_type + } + } + + if (i % 1000 == 0) { + LOG_INFO << "Read nets : " << i << " / " << (int) net_map.size(); + } + } + + omp_destroy_lock(&lck); + + if (mark_drc_num != origin_drc_num) { + LOG_WARNING << "[origin_drc_num] vs [mark_drc_num] : " << origin_drc_num << " vs " << mark_drc_num; + } + + LOG_INFO << "Read nets : " << (int) net_map.size() << " / " << (int) net_map.size(); + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization mark wire drc end..."; +} + +void VecFeatureDrc::markNets() +{ + mark_drc_num = 0; + + ieda::Stats stats; + + omp_lock_t lck; + omp_init_lock(&lck); + + LOG_INFO << "Vectorization mark net drc start..."; + + std::map> net_drc_map; + + auto& layout_layers = _layout->get_layout_layers(); + auto& layer_map = layout_layers.get_layout_layer_map(); + for (int layer_id = 0; layer_id < (int) layer_map.size(); ++layer_id) { + auto& grid = layout_layers.findLayoutLayer(layer_id)->get_grid(); + // 这里改用get_all_nodes()替代原来的get_node_matrix() + auto nodes = grid.get_all_nodes(); + +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < (int) nodes.size(); i++) { + VecNode* node = nodes[i]; + if (node != nullptr && node->get_node_data() != nullptr) { + omp_set_lock(&lck); + net_drc_map[node->get_node_data()->get_net_id()].insert(node->get_node_data()->get_feature().drc_ids.begin(), + node->get_node_data()->get_feature().drc_ids.end()); + omp_unset_lock(&lck); + } + } + } + + int test_num = 0; + for (auto& [net_id, drc_ids] : net_drc_map) { + test_num += drc_ids.size(); + } + + LOG_INFO << "test_num size : " << test_num; + + auto& net_map = _layout->get_graph().get_net_map(); +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < (int) net_map.size(); ++i) { + auto it = net_map.begin(); + std::advance(it, i); + auto& vec_net = it->second; + + auto* net_feature = vec_net.get_feature(true); + net_feature->drc_num += net_drc_map[i].size(); + + // 填充 drc_type + for (auto drc_id : net_drc_map[i]) { + omp_set_lock(&lck); + net_feature->drc_type.push_back(_drc_id_to_type[drc_id]); // 根据 drc_id 获取对应的 drc_type + omp_unset_lock(&lck); + } + + omp_set_lock(&lck); + mark_drc_num += net_drc_map[i].size(); + omp_unset_lock(&lck); + + if (i % 1000 == 0) { + LOG_INFO << "Read nets : " << i << " / " << (int) net_map.size(); + } + } + + omp_destroy_lock(&lck); + + if (mark_drc_num != origin_drc_num) { + LOG_WARNING << "[origin_drc_num] vs [mark_drc_num] : " << origin_drc_num << " vs " << mark_drc_num; + } + + LOG_INFO << "Read nets : " << (int) net_map.size() << " / " << (int) net_map.size(); + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization mark net drc end..."; +} + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/feature/vec_feature_drc.h b/src/vectorization/src/feature/vec_feature_drc.h new file mode 100644 index 0000000000000000000000000000000000000000..020b6e59cf8f777689f86695b81705f3d6d2beda --- /dev/null +++ b/src/vectorization/src/feature/vec_feature_drc.h @@ -0,0 +1,52 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "vec_layout.h" + +namespace ivec { + +class VecFeatureDrc +{ + public: + VecFeatureDrc(VecLayout* layout, std::string drc_path) + { + _layout = layout; + _drc_path = drc_path; + } + ~VecFeatureDrc() {} + + void build(); + + private: + VecLayout* _layout; + std::string _drc_path; + int origin_drc_num = 0; + int mark_drc_num = 0; + + void feature_graph(); + void feature_patch(); + + void markNodes(); + void markWires(); + void markNets(); + + std::map _drc_id_to_type; +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/feature/vec_feature_statis.cpp b/src/vectorization/src/feature/vec_feature_statis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f01b1a6b9bee8de2b7d1371428941010e28d594e --- /dev/null +++ b/src/vectorization/src/feature/vec_feature_statis.cpp @@ -0,0 +1,323 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** + +#include "vec_feature_statis.h" + +#include +#include +#include +#include +#include + +#include "Log.hh" +#include "congestion_api.h" +#include "density_api.h" +#include "idm.h" +#include "omp.h" +#include "timing_api.hh" +#include "usage.hh" +#include "vec_grid_info.h" +#include "wirelength_api.h" + +namespace ivec { +void VecFeatureStatis::build() +{ + feature_patch(); + feature_graph(); +} + +void VecFeatureStatis::feature_graph() +{ + ieda::Stats stats; + + LOG_INFO << "Vectorization build statis feature start..."; + + auto& layout_layers = _layout->get_layout_layers(); + + // get egr_layer_map, which is a map of layer name to a 2D vector of congestion value. + auto egr_layer_map = CONGESTION_API_INST->getEGRMap(); + + // get the number of egr_map's rows and cols. + const auto& first_layer = egr_layer_map.begin()->second; + size_t egr_rows = first_layer.size(); + size_t egr_cols = (egr_rows > 0) ? first_layer[0].size() : 0; + + // calculate the factor to convert egr_map's row and col to the layout's coordinate (x and y). + double row_factor = static_cast(gridInfoInst.ury - gridInfoInst.lly) / egr_rows; + double col_factor = static_cast(gridInfoInst.urx - gridInfoInst.llx) / egr_cols; + + CONGESTION_API_INST->evalNetInfo(); + WIRELENGTH_API_INST->evalNetFlute(); + + auto& net_map = _layout->get_graph().get_net_map(); +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < (int) net_map.size(); ++i) { + auto it = net_map.begin(); + std::advance(it, i); + auto& vec_net = it->second; + + int net_row_min = INT32_MAX; + int net_row_max = INT32_MIN; + int net_col_min = INT32_MAX; + int net_col_max = INT32_MIN; + + auto* net_feature = vec_net.get_feature(true); + + std::string net_name = _layout->findNetName(it->first); + net_feature->aspect_ratio = CONGESTION_API_INST->findAspectRatio(net_name); + net_feature->width = CONGESTION_API_INST->findBBoxWidth(net_name); + net_feature->height = CONGESTION_API_INST->findBBoxHeight(net_name); + net_feature->area = CONGESTION_API_INST->findBBoxArea(net_name); + net_feature->l_ness = CONGESTION_API_INST->findLness(net_name); + net_feature->rsmt = WIRELENGTH_API_INST->findNetFLUTE(net_name); + + /// 初始化 layer_ratio + int16_t min_order = INT8_MAX; // 记录最小层 + int16_t max_order = INT8_MIN; // 记录最大层 + int layer_order_top = layout_layers.get_layer_order_top(); + int layer_order_bottom = layout_layers.get_layer_order_bottom(); + int num_layers = layer_order_top - layer_order_bottom + 1; // 总布线层数 + net_feature->layer_ratio = std::vector(num_layers, 0); + + for (auto& wire : vec_net.get_wires()) { + auto* wire_feature = wire.get_feature(true); + + for (auto& [node1, node2] : wire.get_paths()) { + if (node1->get_layer_id() == node2->get_layer_id()) { + auto order = node1->get_layer_id(); + auto* layout_layer = layout_layers.findLayoutLayer(order); + auto& grid = layout_layer->get_grid(); + auto layer_name = layout_layer->get_layer_name(); + + /// 更新最小层和最大层 + min_order = std::min(min_order, order); + max_order = std::max(max_order, order); + /// 更新 layer_ratio + if (order >= layer_order_bottom && order <= layer_order_top) { + int layer_index = order - layer_order_bottom; // 计算层的索引 + net_feature->layer_ratio[layer_index] = 1; // 设置为 1,表示该层有线经过 + } + + /// set feature + wire_feature->wire_width = layout_layer->get_wire_width(); + + int min_row = std::min(node1->get_row_id(), node2->get_row_id()); + int max_row = std::max(node1->get_row_id(), node2->get_row_id()); + int min_col = std::min(node1->get_col_id(), node2->get_col_id()); + int max_col = std::max(node1->get_col_id(), node2->get_col_id()); + + net_row_min = std::min(net_row_min, min_row); + net_row_max = std::max(net_row_max, max_row); + net_col_min = std::min(net_col_min, min_col); + net_col_max = std::max(net_col_max, max_col); + + // transform the row and col index of node to the row and col index of egr_layer_map + int min_node_x = std::min(node1->get_x(), node2->get_x()); + int max_node_x = std::max(node1->get_x(), node2->get_x()); + int min_node_y = std::min(node1->get_y(), node2->get_y()); + int max_node_y = std::max(node1->get_y(), node2->get_y()); + + int trans_min_row = static_cast(min_node_y / row_factor); + int trans_max_row = static_cast(max_node_y / row_factor); + int trans_min_col = static_cast(min_node_x / col_factor); + int trans_max_col = static_cast(max_node_x / col_factor); + + /// congestion + int sum_congestion = 0; + int trans_grid_count = 0; + + for (int r = trans_min_row; r <= trans_max_row; ++r) { + for (int c = trans_min_col; c <= trans_max_col; ++c) { + sum_congestion += egr_layer_map[layer_name][r][c]; + trans_grid_count++; + } + } + + if (trans_grid_count > 0) { + wire_feature->congestion += ((double) sum_congestion / trans_grid_count); + } else { + wire_feature->congestion = 0; + } + + int horizontal_len = (max_col - min_col) * gridInfoInst.x_step; + int vertical_len = (max_row - min_row) * gridInfoInst.y_step; + + wire_feature->wire_len += (horizontal_len + vertical_len); + wire_feature->wire_density = wire_feature->wire_len * wire_feature->wire_width / static_cast(net_feature->area); + + /// some feature label on node + for (int row = min_row; row <= max_row; ++row) { + for (int col = min_col; col <= max_col; ++col) { + auto* node = grid.get_node(row, col); + if (node == nullptr || node->get_node_data() == nullptr) { + continue; + } + } + } + } else { + /// via feature + net_feature->via_num += 1; + } + } + + net_feature->wire_len += wire_feature->wire_len; + net_feature->llx = gridInfoInst.calculate_x(net_col_min); + net_feature->urx = gridInfoInst.calculate_x(net_col_max); + net_feature->lly = gridInfoInst.calculate_y(net_row_min); + net_feature->ury = gridInfoInst.calculate_y(net_row_max); + net_feature->fanout = vec_net.get_pin_ids().size() - 1; + } + + /// 计算 BBox体积 + if (min_order != INT32_MAX && max_order != INT32_MIN) { + int total_height = (max_order - min_order); + if (total_height == 0) { + total_height = 1; // 如果只在一层,层高为单层高度 + } + net_feature->volume = net_feature->area * total_height; + } else { + net_feature->volume = 0; // 如果没有有效的层,体积为 0 + } + + if (i % 1000 == 0) { + LOG_INFO << "Read nets : " << i << " / " << (int) net_map.size(); + } + } + + LOG_INFO << "Read nets : " << (int) net_map.size() << " / " << (int) net_map.size(); + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization build statis feature end..."; +} + +void VecFeatureStatis::feature_patch() +{ + ieda::Stats stats; + + LOG_INFO << "Vectorization feature patch start..."; + + if (_patch_grid == nullptr) { + LOG_WARNING << "Vectorization feature patch not exist."; + } + + auto& patchs = _patch_grid->get_patchs(); + auto& patch_xy_map = _patch_grid->get_patch_xy_map(); + auto& layout_layers = _layout->get_layout_layers(); + + omp_lock_t lck; + omp_init_lock(&lck); + + // 评估器特征计算,返回的是 patch_id 和 value 的 map + std::map cell_power_map = TimingPower_API_INST->patchPowerMap(patch_xy_map); + std::map cell_timing_map = TimingPower_API_INST->patchTimingMap(patch_xy_map); + // std::map cell_ir_map = TimingPower_API_INST->patchIRDropMap(patch_xy_map); + + std::map pin_density_map = DENSITY_API_INST->patchPinDensity(patch_xy_map); + LOG_INFO << "finish pin_density_map, runtime: " << stats.elapsedRunTime(); + + std::map cell_density_map = DENSITY_API_INST->patchCellDensity(patch_xy_map); + LOG_INFO << "finish cell_density_map, runtime: " << stats.elapsedRunTime(); + + std::map net_density_map = DENSITY_API_INST->patchNetDensity(patch_xy_map); + LOG_INFO << "finish net_density_map, runtime: " << stats.elapsedRunTime(); + + std::map macro_margin_map = DENSITY_API_INST->patchMacroMargin(patch_xy_map); + LOG_INFO << "finish macro_margin_map, runtime: " << stats.elapsedRunTime(); + + std::map rudy_congestion_map = CONGESTION_API_INST->patchRUDYCongestion(patch_xy_map); + LOG_INFO << "finish rudy_congestion_map, runtime: " << stats.elapsedRunTime(); + + std::map egr_congestion_map = CONGESTION_API_INST->patchEGRCongestion(patch_xy_map); + LOG_INFO << "finish egr_congestion_map, runtime: " << stats.elapsedRunTime(); + + std::map> layer_congestion_map = CONGESTION_API_INST->patchLayerEGRCongestion(patch_xy_map); + LOG_INFO << "finish layer_egr_congestion_map, runtime: " << stats.elapsedRunTime(); + +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < (int) patchs.size(); ++i) { + auto it = patchs.begin(); + std::advance(it, i); + auto& patch_id = it->first; + auto& patch = it->second; + + // 根据 patch_id 获取 patch feature + patch.pin_density = pin_density_map[patch_id]; + patch.cell_density = cell_density_map[patch_id]; + patch.net_density = net_density_map[patch_id]; + patch.macro_margin = macro_margin_map[patch_id]; + patch.RUDY_congestion = rudy_congestion_map[patch_id]; + patch.EGR_congestion = egr_congestion_map[patch_id]; + + // // timing, power, ir drop map + auto cell_timing_map_find = cell_timing_map.find(patch_id); + if (cell_timing_map_find != cell_timing_map.end()) { + patch.timing_map = cell_timing_map_find->second; + } + + auto cell_power_map_find = cell_power_map.find(patch_id); + if (cell_power_map_find != cell_power_map.end()) { + patch.power_map = cell_power_map[patch_id]; + } + + // auto cell_ir_map_find = cell_ir_map.find(patch_id); + // if (cell_ir_map_find != cell_ir_map.end()) { + // patch.ir_drop_map = cell_ir_map[patch_id]; + // } + + for (auto& [layer_id, patch_layer] : patch.get_layer_map()) { + patch_layer.wire_width = layout_layers.findLayoutLayer(layer_id)->get_wire_width(); + // 获取每一层对应patch的拥塞值 + std::string layer_name = layout_layers.findLayoutLayer(layer_id)->get_layer_name(); + patch_layer.congestion = layer_congestion_map[patch_id][layer_name]; + + for (auto& [net_id, vec_net] : patch_layer.get_sub_nets()) { + for (auto& wire : vec_net.get_wires()) { + auto* wire_feature = wire.get_feature(true); + + for (auto& [node1, node2] : wire.get_paths()) { + if (node1->get_layer_id() == node2->get_layer_id()) { + auto order = node1->get_layer_id(); + auto* layout_layer = layout_layers.findLayoutLayer(order); + auto layer_name = layout_layer->get_layer_name(); + + int min_row = std::min(node1->get_row_id(), node2->get_row_id()); + int max_row = std::max(node1->get_row_id(), node2->get_row_id()); + int min_col = std::min(node1->get_col_id(), node2->get_col_id()); + int max_col = std::max(node1->get_col_id(), node2->get_col_id()); + int horizontal_len = (max_col - min_col) * gridInfoInst.x_step; + int vertical_len = (max_row - min_row) * gridInfoInst.y_step; + wire_feature->wire_len += (horizontal_len + vertical_len); + patch_layer.wire_len += wire_feature->wire_len; + } + } + } + } + } + + if (i % 1000 == 0) { + LOG_INFO << "Feature patch : " << i << " / " << patchs.size(); + } + } + + omp_destroy_lock(&lck); + + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization feature patch end..."; +} + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/feature/vec_feature_statis.h b/src/vectorization/src/feature/vec_feature_statis.h new file mode 100644 index 0000000000000000000000000000000000000000..804d6cc28518d2d9342269dbb93d112a60fdd5c8 --- /dev/null +++ b/src/vectorization/src/feature/vec_feature_statis.h @@ -0,0 +1,46 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "vec_layout.h" +#include "vec_patch.h" +#include "vec_patch_grid.h" + +namespace ivec { + +class VecFeatureStatis +{ + public: + VecFeatureStatis(VecLayout* layout, VecPatchGrid* patch_grid) + { + _layout = layout; + _patch_grid = patch_grid; + } + ~VecFeatureStatis() {} + + void build(); + + private: + VecLayout* _layout; + VecPatchGrid* _patch_grid; + + void feature_graph(); + void feature_patch(); +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/feature/vec_feature_timing.cpp b/src/vectorization/src/feature/vec_feature_timing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..951e472b72ece01d22a11f6eb94c4332309550d2 --- /dev/null +++ b/src/vectorization/src/feature/vec_feature_timing.cpp @@ -0,0 +1,160 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of +// Sciences Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** + +#include +#include +#include +#include +#include + +#include "Log.hh" +#include "idm.h" +#include "init_sta.hh" +#include "omp.h" +#include "usage.hh" +#include "vec_feature_timing.h" + +namespace ivec { + +void VecFeatureTiming::build() +{ + auto* eval_tp = ieval::InitSTA::getInst(); // evaluate timing and power. + + eval_tp->runVecSTA(_layout, _dir); + + buildNetTimingPowerFeature(); + + auto timing_wire_graph = eval_tp->getTimingWireGraph(); + + std::string yaml_graph_path = _dir + "/wire_graph"; + + if (!std::filesystem::exists(yaml_graph_path)) { + std::filesystem::create_directories(yaml_graph_path); + } + + std::string yaml_graph_file = yaml_graph_path + "/timing_wire_graph.json"; + SaveTimingGraph(timing_wire_graph, yaml_graph_file); + + /// save timing instance graph. + auto timing_instance_graph = eval_tp->getTimingInstanceGraph(); + + yaml_graph_path = _dir + "/instance_graph"; + + if (!std::filesystem::exists(yaml_graph_path)) { + std::filesystem::create_directories(yaml_graph_path); + } + + + yaml_graph_file = yaml_graph_path + "/timing_instance_graph.json"; + SaveTimingInstanceGraph(timing_instance_graph, yaml_graph_file); +} + +void VecFeatureTiming::buildWireTimingPowerFeature(VecNet* vec_net, const std::string& net_name) +{ + auto* eval_tp = ieval::InitSTA::getInst(); + auto [toggle, voltage] = eval_tp->getNetToggleAndVoltage(net_name); + auto all_node_slews = eval_tp->getAllNodesSlew(net_name); + + auto get_node_feature = [this, eval_tp, toggle, voltage, &all_node_slews]( + const auto& net_name, auto& vec_node) -> std::tuple { + std::string node_name; + int pin_id = vec_node->get_node_data()->get_pin_id(); + if (pin_id != -1) { + auto [inst_name, pin_type_name] = _layout->findPinName(pin_id); + auto pin_name = !inst_name.empty() ? (inst_name + ":" + pin_type_name) : pin_type_name; + node_name = pin_name; + } else { + node_name = net_name + ":" + std::to_string(vec_node->get_node_id()); + } + + node_name = ieda::Str::replace(node_name, R"(\\)", ""); + + double resistance = eval_tp->getWireResistance(net_name, node_name); + double capacitance = eval_tp->getWireCapacitance(net_name, node_name); + double slew = all_node_slews.contains(node_name) ? all_node_slews.at(node_name) : 0.0; + double delay = eval_tp->getWireDelay(net_name, node_name); + double power = 0.5 * toggle * voltage * capacitance; + + LOG_INFO_EVERY_N(100) << "node " << node_name << " resistance " << resistance << " cap " << capacitance << " slew " << slew << " delay " + << delay << " power " << power; + + return std::tuple(resistance, capacitance, slew, delay, power); + }; + + for (auto& wire : vec_net->get_wires()) { + auto* wire_feature = wire.get_feature(true); + auto [src, snk] = wire.get_connected_nodes(); + + auto [src_R, src_C, src_slew, src_delay, src_power] = get_node_feature(net_name, src); + auto [snk_R, snk_C, snk_slew, snk_delay, snk_power] = get_node_feature(net_name, snk); + + double wire_resistance = std::abs(snk_R - src_R); + double wire_capacitance = std::abs(snk_C - src_C); + double wire_slew = std::abs(snk_slew - src_slew); + double wire_delay = std::abs(snk_delay - src_delay); + double wire_power = std::abs(snk_power - src_power); + + wire_feature->R = wire_resistance; + wire_feature->C = wire_capacitance; + wire_feature->slew = wire_slew; + wire_feature->delay = wire_delay; + wire_feature->power = wire_power; + } +} + +void VecFeatureTiming::buildNetTimingPowerFeature() +{ + auto* eval_tp = ieval::InitSTA::getInst(); + + auto& vec_graph = _layout->get_graph(); + auto& net_id_map = _layout->get_net_name_map(); + +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < (int) net_id_map.size(); ++i) { + auto it = net_id_map.begin(); + std::advance(it, i); + auto& net_name = it->first; + auto& net_id = it->second; + + if (!eval_tp->getRcNet(net_name)) { + continue; + } + + LOG_INFO << "build net " << net_name << " feature "; + auto* vec_net = vec_graph.get_net(net_id); + auto* net_feature = vec_net->get_feature(true); + + double resistance = eval_tp->getNetResistance(net_name); + double capacitance = eval_tp->getNetCapacitance(net_name); + double slew = eval_tp->getNetSlew(net_name); + double delay = eval_tp->getNetDelay(net_name); + double power = eval_tp->getNetPower(net_name); // TODO(to taosimin), get net power from eval. + + buildWireTimingPowerFeature(vec_net, net_name); + + LOG_INFO << "net " << net_name << " resistance " << resistance << " cap " << capacitance << " slew " << slew << " delay " << delay + << " power " << power; + + net_feature->R = resistance; + net_feature->C = capacitance; + net_feature->slew = slew; + net_feature->delay = delay; + net_feature->power = power; + } +} + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/feature/vec_feature_timing.h b/src/vectorization/src/feature/vec_feature_timing.h new file mode 100644 index 0000000000000000000000000000000000000000..755c929dd64bb103afa4279697bf5cba9db8a640 --- /dev/null +++ b/src/vectorization/src/feature/vec_feature_timing.h @@ -0,0 +1,40 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of +// Sciences Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "vec_layout.h" + +namespace ivec { + +class VecFeatureTiming +{ + public: + VecFeatureTiming(VecLayout* layout, std::string dir) : _layout(layout), _dir(dir) {} + ~VecFeatureTiming() {} + + void build(); + + private: + VecLayout* _layout; + std::string _dir; //!< The directory for the path. + + void buildWireTimingPowerFeature(VecNet* vec_net, const std::string& net_name); + void buildNetTimingPowerFeature(); +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/graph/CMakeLists.txt b/src/vectorization/src/graph/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..cb940a283a2cdf82b3f521958f234d0824c86f7a --- /dev/null +++ b/src/vectorization/src/graph/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(data_manager) \ No newline at end of file diff --git a/src/vectorization/src/graph/data_manager/CMakeLists.txt b/src/vectorization/src/graph/data_manager/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c2484243580bec21ca6310172561b1f8126506c --- /dev/null +++ b/src/vectorization/src/graph/data_manager/CMakeLists.txt @@ -0,0 +1,64 @@ +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +option(BUILD_VEC_GUI "Enable GUI components (default OFF)" OFF) + +if(POLICY CMP0100) + cmake_policy(SET CMP0100 NEW) +endif() + +set(IVEC_GRAPH_DM_SRCS + vec_graph_dm.cpp + vec_graph_check.cc + vec_net_graph_gen.cc +) + +if(BUILD_VEC_GUI) + add_definitions(-DBUILD_VEC_GUI) + + list(APPEND IVEC_GRAPH_DM_SRCS + vec_graph_gui.cc + vec_graph_gui.hh + ) + + find_package(Qt5 COMPONENTS Core Gui Widgets OpenGL REQUIRED) + find_package(OpenGL REQUIRED) +endif() + +add_library(ivec_graph_dm ${IVEC_GRAPH_DM_SRCS}) + +target_link_libraries(ivec_graph_dm + PUBLIC + idb + idm + geometry_db + log + usage + ivec_db + ivec_dm + ivec_layout_db + ivec_util + eval_timing_api +) + +if(BUILD_VEC_GUI) + target_link_libraries(ivec_graph_dm + PUBLIC + Qt5::Core + Qt5::Gui + Qt5::Widgets + Qt5::OpenGL + ${OPENGL_LIBRARIES} + ) +endif() + +target_include_directories(ivec_graph_dm + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${HOME_UTILITY}/json +) + +include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) \ No newline at end of file diff --git a/src/vectorization/src/graph/data_manager/layout-viewer/css/style.css b/src/vectorization/src/graph/data_manager/layout-viewer/css/style.css new file mode 100644 index 0000000000000000000000000000000000000000..712264a6ff26260c4d20307c493430cbfd4888ae --- /dev/null +++ b/src/vectorization/src/graph/data_manager/layout-viewer/css/style.css @@ -0,0 +1,466 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + overflow: hidden; + background: #151515; + color: #eee; +} + +#container { + display: flex; + width: 100vw; + height: 100vh; +} + +#control-panel { + width: 300px; + background: #222; + color: #eee; + padding: 10px; + overflow-y: auto; + border-right: 1px solid #444; +} + +.panel-section { + margin-bottom: 20px; + padding: 10px; + background: #333; + border-radius: 4px; +} + +.panel-section h3 { + margin-bottom: 10px; + color: #ccc; + font-size: 14px; +} + +.control-btn { + background: #444; + color: #eee; + border: 1px solid #555; + border-radius: 4px; + padding: 8px 12px; + cursor: pointer; + width: 100%; + margin-bottom: 5px; + font-size: 12px; +} + +.control-btn:hover { + background: #555; +} + +.control-btn.active { + background: #666; +} + +#search-input { + width: 100%; + padding: 6px; + border: 1px solid #444; + border-radius: 4px; + background: #333; + color: #eee; + margin-bottom: 10px; +} + +.checkbox-group { + display: flex; + gap: 10px; + margin-bottom: 10px; +} + +.checkbox-group label { + font-size: 12px; + cursor: pointer; +} + +.control-buttons { + display: flex; + align-items: center; + gap: 10px; +} + +.rainbow-btn { + width: 30px; + height: 30px; + border-radius: 50%; + border: 2px solid #666; + background: linear-gradient(45deg, + red, orange, yellow, green, cyan, blue, purple); + cursor: pointer; +} + +#group-filtered { + flex: 1; +} + +#viewport { + flex: 1; + position: relative; +} + +#canvas { + width: 100%; + height: 100%; + display: block; +} + +#class-table { + max-height: 300px; + overflow-y: auto; +} + +.table-header { + display: grid; + grid-template-columns: 1fr auto auto auto; + gap: 10px; + padding: 5px; + background: #444; + font-weight: bold; + font-size: 12px; + border-radius: 3px; + margin-bottom: 5px; +} + +.table-row { + display: grid; + grid-template-columns: 1fr auto auto auto; + gap: 10px; + padding: 5px; + border-radius: 3px; + margin-bottom: 2px; + background: #2a2a2a; + font-size: 11px; + align-items: center; +} + +.table-row>span:first-child { + /* Class name column - allow text wrapping and set min width */ + word-break: break-word; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; +} + +.table-row:hover { + background: #3a3a3a; +} + +.color-cell { + width: 20px; + height: 20px; + border-radius: 3px; + cursor: pointer; + border: 1px solid #555; +} + +.tooltip { + position: absolute; + background: rgba(0, 0, 0, 0.8); + color: white; + padding: 5px 8px; + border-radius: 3px; + pointer-events: none; + z-index: 1000; + font-size: 12px; + display: none; +} + +#file-status { + margin-top: 10px; + padding: 5px; + border-radius: 3px; + font-size: 12px; + min-height: 20px; +} + +.status-success { + background: #2d5a2d; + color: #90ee90; +} + +.status-error { + background: #5a2d2d; + color: #ff9090; +} + +.status-info { + background: #2d4a5a; + color: #90d0ff; +} + +#canvas { + width: 100%; + height: 100%; + display: block; + cursor: default; +} + +#canvas:active { + cursor: grabbing; +} + +.control-btn.active { + background: #666; + border-color: #777; +} + +/* Modal styles */ +.modal { + display: none; + position: fixed; + z-index: 1000; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); +} + +.modal-content { + background-color: #333; + margin: 15% auto; + padding: 0; + border: 1px solid #555; + border-radius: 8px; + width: 400px; + max-width: 90%; +} + +.modal-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 15px 20px; + background-color: #444; + border-bottom: 1px solid #555; + border-radius: 8px 8px 0 0; +} + +.modal-header h3 { + margin: 0; + color: #eee; +} + +.close-btn { + color: #aaa; + font-size: 28px; + font-weight: bold; + cursor: pointer; +} + +.close-btn:hover { + color: #fff; +} + +.modal-body { + padding: 20px; +} + +.color-picker-container { + display: flex; + align-items: center; + gap: 15px; + margin-bottom: 15px; +} + +#color-picker { + width: 60px; + height: 40px; + border: none; + border-radius: 4px; + cursor: pointer; +} + +.color-preview { + width: 40px; + height: 40px; + border: 2px solid #555; + border-radius: 4px; + background-color: #ff0000; +} + +.rgb-inputs { + display: flex; + gap: 10px; + margin-bottom: 20px; +} + +.rgb-inputs label { + display: flex; + flex-direction: column; + gap: 5px; + flex: 1; + font-size: 12px; +} + +.rgb-inputs input { + padding: 5px; + border: 1px solid #555; + border-radius: 4px; + background: #222; + color: #eee; + text-align: center; +} + +.modal-buttons { + display: flex; + gap: 10px; + justify-content: flex-end; +} + +.modal-buttons .control-btn { + width: auto; + margin: 0; +} + +.group-selection, +.new-group { + margin-bottom: 15px; +} + +.group-selection label, +.new-group label { + display: block; + margin-bottom: 5px; + font-size: 12px; +} + +#group-select, +#new-group-name { + width: 100%; + padding: 8px; + border: 1px solid #555; + border-radius: 4px; + background: #222; + color: #eee; +} + +/* Groups section styles */ +#groups-container { + max-height: 300px; + overflow-y: auto; +} + +.group-item { + margin-bottom: 10px; + border: 1px solid #444; + border-radius: 4px; + background: #2a2a2a; +} + +.group-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 10px; + background: #3a3a3a; + cursor: pointer; + border-radius: 4px 4px 0 0; +} + +.group-header:hover { + background: #4a4a4a; +} + +.group-controls { + display: flex; + gap: 5px; + align-items: center; +} + +.group-control-btn { + background: #555; + color: #eee; + border: 1px solid #666; + border-radius: 3px; + padding: 4px 8px; + cursor: pointer; + font-size: 10px; + white-space: nowrap; +} + +.group-control-btn:hover { + background: #666; +} + +.group-color-btn { + background: linear-gradient(45deg, #ff4444, #44ff44, #4444ff); +} + +.group-dissolve-btn { + background: #cc4444; + border-color: #bb3333; +} + +.group-dissolve-btn:hover { + background: #dd5555; +} + +.group-blur-btn { + background: #666; + opacity: 0.8; +} + +.group-name { + font-weight: bold; + font-size: 12px; +} + +.group-toggle { + font-size: 14px; + color: #aaa; +} + +.group-content { + padding: 5px; + display: none; +} + +.group-content.expanded { + display: block; +} + +.group-item-row { + display: grid; + grid-template-columns: 1fr auto auto; + gap: 10px; + padding: 3px 5px; + align-items: center; + font-size: 11px; + border-radius: 2px; + margin-bottom: 2px; + background: #2a2a2a; +} + +.group-item-row>span:first-child { + /* Class name column - allow text wrapping and set min width */ + word-break: break-word; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; +} + +.group-item-row:hover { + background: #3a3a3a; +} + +.group-btn { + background: #444; + color: #eee; + border: 1px solid #555; + border-radius: 3px; + padding: 4px 8px; + cursor: pointer; + font-size: 10px; +} + +.group-btn:hover { + background: #555; +} \ No newline at end of file diff --git a/src/vectorization/src/graph/data_manager/layout-viewer/index.html b/src/vectorization/src/graph/data_manager/layout-viewer/index.html new file mode 100644 index 0000000000000000000000000000000000000000..233a34a06128784a37b7c118c063cf57853ca810 --- /dev/null +++ b/src/vectorization/src/graph/data_manager/layout-viewer/index.html @@ -0,0 +1,128 @@ + + + + + + + 3D Layout Viewer + + + + + + +
+
+
+

View Controls

+ + + +
+ +
+

Data Import

+ + +
+
+ +
+

Filter & Search

+ +
+ + + +
+
+ + +
+
+ +
+

Data Filtering

+
+
+ Class + Visible + Color + Group +
+
+
+
+ +
+

Groups

+
+
+
+
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/vectorization/src/graph/data_manager/layout-viewer/js/controls-manager.js b/src/vectorization/src/graph/data_manager/layout-viewer/js/controls-manager.js new file mode 100644 index 0000000000000000000000000000000000000000..38455ee7231adaff773c78f478aefbe257fed72f --- /dev/null +++ b/src/vectorization/src/graph/data_manager/layout-viewer/js/controls-manager.js @@ -0,0 +1,785 @@ +class ControlsManager { + constructor(sceneManager) { + this.sceneManager = sceneManager; + this.dataManager = sceneManager.getDataManager(); + + this.searchFilter = ''; + this.isRegexFilter = false; + this.filteredClasses = new Set(); + this.groups = new Map(); // groupName -> Set of classNames + this.classGroups = new Map(); // className -> Set of groupNames (allow multiple groups) + + this.currentColorCallback = null; + this.currentGroupCallback = null; + + this.setupEventListeners(); + } + + setupEventListeners() { + // View controls + document.getElementById('rotation-mode').addEventListener('click', (e) => { + const btn = e.target; + const isRotation = !btn.classList.contains('active'); + btn.classList.toggle('active'); + btn.textContent = isRotation ? 'Rotation Mode (On)' : 'Rotation Mode (Off)'; + btn.title = isRotation ? 'Hold Ctrl for world Z-axis only rotation' : 'Click to enable rotation mode'; + + // Set rotation mode in scene manager + this.sceneManager.setRotationMode(isRotation); + }); + + document.getElementById('reset-view').addEventListener('click', () => { + this.sceneManager.resetView(); + }); + + document.getElementById('show-axes').addEventListener('click', () => { + this.sceneManager.toggleAxes(); + }); + + // File import + document.getElementById('import-btn').addEventListener('click', () => { + document.getElementById('file-input').click(); + }); + + document.getElementById('file-input').addEventListener('change', (e) => { + this.handleFileImport(e.target.files[0]); + }); + + // Search and filter + document.getElementById('search-input').addEventListener('input', (e) => { + this.handleSearch(e.target.value); + }); + + document.getElementById('regex-filter').addEventListener('change', (e) => { + this.isRegexFilter = e.target.checked; + this.handleSearch(this.searchFilter); // Re-filter with current search text + }); + + document.getElementById('hide-all').addEventListener('change', (e) => { + if (e.target.checked) { + document.getElementById('show-all').checked = false; + this.setAllClassesVisibility(false); + } + }); + + document.getElementById('show-all').addEventListener('change', (e) => { + if (e.target.checked) { + document.getElementById('hide-all').checked = false; + this.setAllClassesVisibility(true); + } + }); + + document.getElementById('unified-color').addEventListener('click', () => { + this.handleUnifiedColor(); + }); + + document.getElementById('group-filtered').addEventListener('click', () => { + this.handleGroupFiltered(); + }); + + // Color picker modal + this.setupColorPickerModal(); + + // Group modal + this.setupGroupModal(); + } + + setupColorPickerModal() { + const modal = document.getElementById('color-picker-modal'); + const colorPicker = document.getElementById('color-picker'); + const colorPreview = document.getElementById('color-preview'); + const redInput = document.getElementById('red-input'); + const greenInput = document.getElementById('green-input'); + const blueInput = document.getElementById('blue-input'); + const applyBtn = document.getElementById('apply-color'); + const cancelBtn = document.getElementById('cancel-color'); + const closeBtn = modal.querySelector('.close-btn'); + + // Close modal events + [closeBtn, cancelBtn].forEach(btn => { + btn.addEventListener('click', () => { + modal.style.display = 'none'; + this.currentColorCallback = null; + }); + }); + + // Click outside to close + modal.addEventListener('click', (e) => { + if (e.target === modal) { + modal.style.display = 'none'; + this.currentColorCallback = null; + } + }); + + // Color picker change + colorPicker.addEventListener('input', (e) => { + const hex = e.target.value; + const rgb = this.hexToRgb(hex); + redInput.value = rgb.r; + greenInput.value = rgb.g; + blueInput.value = rgb.b; + colorPreview.style.backgroundColor = hex; + }); + + // RGB input changes + [redInput, greenInput, blueInput].forEach(input => { + input.addEventListener('input', () => { + const r = Math.max(0, Math.min(255, parseInt(redInput.value) || 0)); + const g = Math.max(0, Math.min(255, parseInt(greenInput.value) || 0)); + const b = Math.max(0, Math.min(255, parseInt(blueInput.value) || 0)); + + redInput.value = r; + greenInput.value = g; + blueInput.value = b; + + const hex = this.rgbToHex(r/255, g/255, b/255); + colorPicker.value = hex; + colorPreview.style.backgroundColor = hex; + }); + }); + + // Apply color + applyBtn.addEventListener('click', () => { + if (this.currentColorCallback) { + const r = parseInt(redInput.value) / 255; + const g = parseInt(greenInput.value) / 255; + const b = parseInt(blueInput.value) / 255; + this.currentColorCallback({ r, g, b }); + } + modal.style.display = 'none'; + this.currentColorCallback = null; + }); + } + + setupGroupModal() { + const modal = document.getElementById('group-modal'); + const groupSelect = document.getElementById('group-select'); + const newGroupInput = document.getElementById('new-group-name'); + const assignBtn = document.getElementById('assign-group'); + const cancelBtn = document.getElementById('cancel-group'); + const closeBtn = modal.querySelector('.close-btn'); + + // Close modal events + [closeBtn, cancelBtn].forEach(btn => { + btn.addEventListener('click', () => { + modal.style.display = 'none'; + this.currentGroupCallback = null; + }); + }); + + // Click outside to close + modal.addEventListener('click', (e) => { + if (e.target === modal) { + modal.style.display = 'none'; + this.currentGroupCallback = null; + } + }); + + // Clear new group input when selecting existing group + groupSelect.addEventListener('change', () => { + if (groupSelect.value) { + newGroupInput.value = ''; + } + }); + + // Clear group selection when typing new group name + newGroupInput.addEventListener('input', () => { + if (newGroupInput.value.trim()) { + groupSelect.value = ''; + } + }); + + // Assign to group + assignBtn.addEventListener('click', () => { + const selectedGroup = groupSelect.value; + const newGroupName = newGroupInput.value.trim(); + + if (selectedGroup || newGroupName) { + const groupName = newGroupName || selectedGroup; + if (this.currentGroupCallback) { + this.currentGroupCallback(groupName); + } + } + + modal.style.display = 'none'; + this.currentGroupCallback = null; + }); + } + + showColorPicker(initialColor, callback) { + const modal = document.getElementById('color-picker-modal'); + const colorPicker = document.getElementById('color-picker'); + const colorPreview = document.getElementById('color-preview'); + const redInput = document.getElementById('red-input'); + const greenInput = document.getElementById('green-input'); + const blueInput = document.getElementById('blue-input'); + + // Set initial values + const hex = this.rgbToHex(initialColor.r, initialColor.g, initialColor.b); + colorPicker.value = hex; + colorPreview.style.backgroundColor = hex; + redInput.value = Math.round(initialColor.r * 255); + greenInput.value = Math.round(initialColor.g * 255); + blueInput.value = Math.round(initialColor.b * 255); + + this.currentColorCallback = callback; + modal.style.display = 'block'; + } + + showGroupModal(callback) { + const modal = document.getElementById('group-modal'); + const groupSelect = document.getElementById('group-select'); + const newGroupInput = document.getElementById('new-group-name'); + + // Populate group options + groupSelect.innerHTML = ''; + for (const groupName of this.groups.keys()) { + const option = document.createElement('option'); + option.value = groupName; + option.textContent = groupName; + groupSelect.appendChild(option); + } + + // Clear inputs + groupSelect.value = ''; + newGroupInput.value = ''; + + this.currentGroupCallback = callback; + modal.style.display = 'block'; + } + + async handleFileImport(file) { + if (!file) return; + + const statusDiv = document.getElementById('file-status'); + + try { + statusDiv.className = 'status-info'; + statusDiv.textContent = 'Uploading file...'; + + const formData = new FormData(); + formData.append('jsonFile', file); + + const response = await fetch('/upload', { + method: 'POST', + body: formData + }); + + const result = await response.json(); + + if (result.success) { + statusDiv.className = 'status-success'; + statusDiv.textContent = `Successfully loaded ${file.name}`; + + this.sceneManager.loadFromJSON(result.data); + this.updateClassTable(); + } else { + throw new Error(result.error || 'Upload failed'); + } + } catch (error) { + console.error('File import error:', error); + statusDiv.className = 'status-error'; + statusDiv.textContent = `Error: ${error.message}`; + } + + // Reset file input + document.getElementById('file-input').value = ''; + } + + handleSearch(searchText) { + this.searchFilter = searchText; + this.updateClassTable(); + } + + setAllClassesVisibility(visible) { + this.dataManager.getAllClasses().forEach(className => { + this.dataManager.setClassVisibility(className, visible); + this.sceneManager.setClassVisibility(className, visible); + }); + this.updateClassTable(); + } + + handleUnifiedColor() { + // Get currently filtered classes only + const filteredClasses = this.getFilteredClasses(); + + this.showColorPicker({ r: 1, g: 0, b: 0 }, (color) => { + filteredClasses.forEach(className => { + if (this.dataManager.isClassVisible(className)) { + this.dataManager.setClassColor(className, color); + this.sceneManager.setClassColor(className, color); + } + }); + this.updateClassTable(); + }); + } + + // Helper method to get currently filtered classes + getFilteredClasses() { + const allClasses = this.dataManager.getAllClasses(); + + if (this.searchFilter === '') { + return allClasses; + } else if (this.isRegexFilter) { + try { + const regex = new RegExp(this.searchFilter, 'i'); + return allClasses.filter(className => regex.test(className)); + } catch (e) { + // Invalid regex, fall back to plain text search + const lowerFilter = this.searchFilter.toLowerCase(); + return allClasses.filter(className => + className.toLowerCase().includes(lowerFilter) + ); + } + } else { + const lowerFilter = this.searchFilter.toLowerCase(); + return allClasses.filter(className => + className.toLowerCase().includes(lowerFilter) + ); + } + } + + handleGroupFiltered() { + const allClasses = this.dataManager.getAllClasses(); + + let filteredClasses; + if (this.searchFilter === '') { + filteredClasses = allClasses; + } else if (this.isRegexFilter) { + try { + const regex = new RegExp(this.searchFilter, 'i'); + filteredClasses = allClasses.filter(className => regex.test(className)); + } catch (e) { + // Invalid regex, fall back to plain text search + const lowerFilter = this.searchFilter.toLowerCase(); + filteredClasses = allClasses.filter(className => + className.toLowerCase().includes(lowerFilter) + ); + } + } else { + const lowerFilter = this.searchFilter.toLowerCase(); + filteredClasses = allClasses.filter(className => + className.toLowerCase().includes(lowerFilter) + ); + } + + if (filteredClasses.length === 0) { + alert('No classes match the current filter.'); + return; + } + + this.showGroupModal((groupName) => { + this.assignClassesToGroup(filteredClasses, groupName); + }); + } + + assignClassesToGroup(classNames, groupName) { + // Add classes to new group (allow multiple group membership) + if (!this.groups.has(groupName)) { + this.groups.set(groupName, new Set()); + } + + classNames.forEach(className => { + // Add class to the group + this.groups.get(groupName).add(className); + + // Add group to class's group set + if (!this.classGroups.has(className)) { + this.classGroups.set(className, new Set()); + } + this.classGroups.get(className).add(groupName); + }); + + this.updateClassTable(); + this.updateGroupsDisplay(); + + console.log(`Added ${classNames.length} classes to group "${groupName}". Classes can belong to multiple groups simultaneously.`); + } + + assignClassToGroup(className, groupName) { + this.assignClassesToGroup([className], groupName); + } + + updateClassTable() { + const classList = document.getElementById('class-list'); + classList.innerHTML = ''; + + const allClasses = this.dataManager.getAllClasses(); + + let filteredClasses; + if (this.searchFilter === '') { + filteredClasses = allClasses; + } else if (this.isRegexFilter) { + try { + const regex = new RegExp(this.searchFilter, 'i'); + filteredClasses = allClasses.filter(className => regex.test(className)); + } catch (e) { + // Invalid regex, fall back to plain text search + const lowerFilter = this.searchFilter.toLowerCase(); + filteredClasses = allClasses.filter(className => + className.toLowerCase().includes(lowerFilter) + ); + } + } else { + const lowerFilter = this.searchFilter.toLowerCase(); + filteredClasses = allClasses.filter(className => + className.toLowerCase().includes(lowerFilter) + ); + } + + filteredClasses.forEach(className => { + const row = this.createClassRow(className); + classList.appendChild(row); + }); + } + + createClassRow(className) { + const row = document.createElement('div'); + row.className = 'table-row'; + + // Class name + const nameCell = document.createElement('span'); + nameCell.textContent = className; + nameCell.title = className; + + // Visibility checkbox + const visibleCell = document.createElement('input'); + visibleCell.type = 'checkbox'; + visibleCell.checked = this.dataManager.isClassVisible(className); + visibleCell.addEventListener('change', (e) => { + this.dataManager.setClassVisibility(className, e.target.checked); + this.sceneManager.setClassVisibility(className, e.target.checked); + }); + + // Color picker + const color = this.dataManager.getClassColor(className); + const colorCell = document.createElement('div'); + colorCell.className = 'color-cell'; + colorCell.style.backgroundColor = this.rgbToHex(color.r, color.g, color.b); + colorCell.addEventListener('click', () => { + this.showColorPicker(color, (newColor) => { + this.dataManager.setClassColor(className, newColor); + this.sceneManager.setClassColor(className, newColor); + colorCell.style.backgroundColor = this.rgbToHex(newColor.r, newColor.g, newColor.b); + }); + }); + + // Group button + const groupBtn = document.createElement('button'); + groupBtn.className = 'group-btn'; + groupBtn.textContent = 'Group'; + groupBtn.addEventListener('click', () => { + this.showGroupModal((groupName) => { + this.assignClassToGroup(className, groupName); + }); + }); + + row.appendChild(nameCell); + row.appendChild(visibleCell); + row.appendChild(colorCell); + row.appendChild(groupBtn); + + return row; + } + + updateGroupsDisplay() { + const groupsList = document.getElementById('groups-list'); + groupsList.innerHTML = ''; + + for (const [groupName, classSet] of this.groups.entries()) { + if (classSet.size === 0) continue; + + const groupItem = this.createGroupItem(groupName, classSet); + groupsList.appendChild(groupItem); + } + } + + createGroupItem(groupName, classSet) { + const groupItem = document.createElement('div'); + groupItem.className = 'group-item'; + + // Group header + const groupHeader = document.createElement('div'); + groupHeader.className = 'group-header'; + + const groupNameSpan = document.createElement('span'); + groupNameSpan.className = 'group-name'; + groupNameSpan.textContent = `${groupName} (${classSet.size})`; + + // Group controls container + const groupControls = document.createElement('div'); + groupControls.className = 'group-controls'; + + // Group visibility toggle + const groupVisibleBtn = document.createElement('button'); + groupVisibleBtn.className = 'group-control-btn'; + groupVisibleBtn.textContent = 'Visible'; + groupVisibleBtn.title = 'Toggle visibility for all items in this group'; + groupVisibleBtn.addEventListener('click', (e) => { + e.stopPropagation(); + this.toggleGroupVisibility(groupName, classSet); + }); + + // Group color button + const groupColorBtn = document.createElement('button'); + groupColorBtn.className = 'group-control-btn group-color-btn'; + groupColorBtn.textContent = 'Color'; + groupColorBtn.title = 'Set color for all items in this group'; + groupColorBtn.addEventListener('click', (e) => { + e.stopPropagation(); + this.setGroupColor(groupName, classSet); + }); + + // Group blur button + const groupBlurBtn = document.createElement('button'); + groupBlurBtn.className = 'group-control-btn group-blur-btn'; + groupBlurBtn.textContent = 'Blur'; + groupBlurBtn.title = 'Toggle transparency for all items in this group'; + groupBlurBtn.addEventListener('click', (e) => { + e.stopPropagation(); + this.toggleGroupBlur(groupName, classSet); + }); + + // Group dissolve button + const groupDissolveBtn = document.createElement('button'); + groupDissolveBtn.className = 'group-control-btn group-dissolve-btn'; + groupDissolveBtn.textContent = 'Dissolve'; + groupDissolveBtn.title = 'Delete this group (classes remain visible)'; + groupDissolveBtn.addEventListener('click', (e) => { + e.stopPropagation(); + this.dissolveGroup(groupName); + }); + + const toggleSpan = document.createElement('span'); + toggleSpan.className = 'group-toggle'; + toggleSpan.textContent = '▼'; + + groupControls.appendChild(groupVisibleBtn); + groupControls.appendChild(groupColorBtn); + groupControls.appendChild(groupBlurBtn); + groupControls.appendChild(groupDissolveBtn); + + groupHeader.appendChild(groupNameSpan); + groupHeader.appendChild(groupControls); + groupHeader.appendChild(toggleSpan); + + // Group content + const groupContent = document.createElement('div'); + groupContent.className = 'group-content'; + + for (const className of classSet) { + const itemRow = this.createGroupItemRow(className); + groupContent.appendChild(itemRow); + } + + // Toggle functionality + groupHeader.addEventListener('click', (e) => { + // Don't toggle if clicking on control buttons + if (e.target.classList.contains('group-control-btn')) { + return; + } + const isExpanded = groupContent.classList.toggle('expanded'); + toggleSpan.textContent = isExpanded ? '▲' : '▼'; + }); + + groupItem.appendChild(groupHeader); + groupItem.appendChild(groupContent); + + return groupItem; + } + + createGroupItemRow(className) { + const row = document.createElement('div'); + row.className = 'group-item-row'; + + // Class name + const nameSpan = document.createElement('span'); + nameSpan.textContent = className; + nameSpan.title = className; + + // Visibility checkbox + const visibleInput = document.createElement('input'); + visibleInput.type = 'checkbox'; + visibleInput.checked = this.dataManager.isClassVisible(className); + visibleInput.addEventListener('change', (e) => { + this.dataManager.setClassVisibility(className, e.target.checked); + this.sceneManager.setClassVisibility(className, e.target.checked); + this.updateClassTable(); // Update main table as well + }); + + // Color picker + const color = this.dataManager.getClassColor(className); + const colorDiv = document.createElement('div'); + colorDiv.className = 'color-cell'; + colorDiv.style.backgroundColor = this.rgbToHex(color.r, color.g, color.b); + colorDiv.addEventListener('click', () => { + this.showColorPicker(color, (newColor) => { + this.dataManager.setClassColor(className, newColor); + this.sceneManager.setClassColor(className, newColor); + colorDiv.style.backgroundColor = this.rgbToHex(newColor.r, newColor.g, newColor.b); + this.updateClassTable(); // Update main table as well + }); + }); + + row.appendChild(nameSpan); + row.appendChild(visibleInput); + row.appendChild(colorDiv); + + return row; + } + + toggleGroupVisibility(groupName, classSet) { + // Check if any classes in the group are currently visible + let hasVisibleClasses = false; + for (const className of classSet) { + if (this.dataManager.isClassVisible(className)) { + hasVisibleClasses = true; + break; + } + } + + // Toggle: if any are visible, hide all; if all are hidden, show all + const newVisibility = !hasVisibleClasses; + + let conflictCount = 0; + for (const className of classSet) { + // Check for conflicts with other groups + const classGroupSet = this.classGroups.get(className); + if (classGroupSet && classGroupSet.size > 1) { + conflictCount++; + console.log(`Visibility conflict resolved for "${className}" - applying group "${groupName}" settings (class belongs to ${classGroupSet.size} groups)`); + } + + this.dataManager.setClassVisibility(className, newVisibility); + this.sceneManager.setClassVisibility(className, newVisibility); + } + + if (conflictCount > 0) { + console.log(`Group "${groupName}" visibility operation completed with ${conflictCount} multi-group conflicts resolved via direct overwriting`); + } + + // Update both main table and group display + this.updateClassTable(); + this.updateGroupsDisplay(); + } + + setGroupColor(groupName, classSet) { + // Get the color of the first class as the initial color + const firstClassName = classSet.values().next().value; + const initialColor = this.dataManager.getClassColor(firstClassName); + + this.showColorPicker(initialColor, (newColor) => { + let conflictCount = 0; + // Apply color to all classes in the group + for (const className of classSet) { + // Check for conflicts with other groups + const classGroupSet = this.classGroups.get(className); + if (classGroupSet && classGroupSet.size > 1) { + conflictCount++; + console.log(`Color conflict resolved for "${className}" - applying group "${groupName}" settings (class belongs to ${classGroupSet.size} groups)`); + } + + this.dataManager.setClassColor(className, newColor); + this.sceneManager.setClassColor(className, newColor); + } + + if (conflictCount > 0) { + console.log(`Group "${groupName}" color operation completed with ${conflictCount} multi-group conflicts resolved via direct overwriting`); + } + + // Update both main table and group display + this.updateClassTable(); + this.updateGroupsDisplay(); + }); + } + + toggleGroupBlur(groupName, classSet) { + // Check if any classes in the group are currently blurred (have alpha < 1) + let hasBlurredClasses = false; + for (const className of classSet) { + const color = this.dataManager.getClassColor(className); + if (color.a !== undefined && color.a < 1) { + hasBlurredClasses = true; + break; + } + } + + // Toggle: if any are blurred, remove blur; if none are blurred, add blur + const newAlpha = hasBlurredClasses ? 1.0 : 0.1; + + let conflictCount = 0; + for (const className of classSet) { + // Check for conflicts with other groups + const classGroupSet = this.classGroups.get(className); + if (classGroupSet && classGroupSet.size > 1) { + conflictCount++; + console.log(`Blur conflict resolved for "${className}" - applying group "${groupName}" settings (class belongs to ${classGroupSet.size} groups)`); + } + + const color = this.dataManager.getClassColor(className); + const newColor = { ...color, a: newAlpha }; + this.dataManager.setClassColor(className, newColor); + this.sceneManager.setClassColor(className, newColor); + } + + if (conflictCount > 0) { + console.log(`Group "${groupName}" blur operation completed with ${conflictCount} multi-group conflicts resolved via direct overwriting`); + } + + // Update both main table and group display + this.updateClassTable(); + this.updateGroupsDisplay(); + } + + dissolveGroup(groupName) { + // Confirm before dissolving + if (!confirm(`Are you sure you want to dissolve the group "${groupName}"? All classes will remain visible but ungrouped.`)) { + return; + } + + // Get classes in the group + const classSet = this.groups.get(groupName); + if (!classSet) { + console.warn(`Group "${groupName}" not found`); + return; + } + + // Remove group mappings for all classes in the group + for (const className of classSet) { + const classGroupSet = this.classGroups.get(className); + if (classGroupSet) { + classGroupSet.delete(groupName); + // If this was the last group for this class, remove the entry entirely + if (classGroupSet.size === 0) { + this.classGroups.delete(className); + } + } + } + + // Remove the group itself + this.groups.delete(groupName); + + // Update displays + this.updateClassTable(); + this.updateGroupsDisplay(); + + console.log(`Dissolved group "${groupName}" containing ${classSet.size} classes. Classes may still belong to other groups.`); + } + + hexToRgb(hex) { + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; + } + + rgbToHex(r, g, b) { + const toHex = (c) => { + const hex = Math.round(c * 255).toString(16).padStart(2, '0'); + return hex; + }; + return `#${toHex(r)}${toHex(g)}${toHex(b)}`; + } +} diff --git a/src/vectorization/src/graph/data_manager/layout-viewer/js/data-manager.js b/src/vectorization/src/graph/data_manager/layout-viewer/js/data-manager.js new file mode 100644 index 0000000000000000000000000000000000000000..a02a1d798a4963a7086748acd398a4a22e78183c --- /dev/null +++ b/src/vectorization/src/graph/data_manager/layout-viewer/js/data-manager.js @@ -0,0 +1,188 @@ +class DataManager { + constructor() { + this.shapes = new Map(); // className -> shapes array + this.classVisibility = new Map(); + this.classColors = new Map(); + this.bounds = { + min: { x: Infinity, y: Infinity, z: Infinity }, + max: { x: -Infinity, y: -Infinity, z: -Infinity } + }; + } + + addWire(x1, y1, z, x2, y2, z2, comment, shapeClass, color) { + // Only allow horizontal or vertical lines + if (!(Math.abs(x1 - x2) < 1e-6 || Math.abs(y1 - y2) < 1e-6)) { + return; + } + + const shape = { + type: 'Wire', + x1, y1, z1: z, + x2, y2, z2: z, + comment, + shapeClass, + width: 5.0 + }; + + this._addShape(shape, shapeClass, color); + } + + addRect(x1, y1, z, x2, y2, z2, comment, shapeClass, color) { + const shape = { + type: 'Rect', + x1, y1, z1: z, + x2, y2, z2: z, + comment, + shapeClass, + width: 0.0 + }; + + this._addShape(shape, shapeClass, color); + } + + addVia(x, y, z1, z2, comment, shapeClass, color) { + const shape = { + type: 'Via', + x1: x, y1: y, z1, + x2: x, y2: y, z2, + comment, + shapeClass, + width: 5.0 + }; + + this._addShape(shape, shapeClass, color); + } + + _addShape(shape, shapeClass, color) { + if (!this.shapes.has(shapeClass)) { + this.shapes.set(shapeClass, []); + this.classVisibility.set(shapeClass, true); + this.classColors.set(shapeClass, color || { r: 1, g: 1, b: 1 }); + } + + this.shapes.get(shapeClass).push(shape); + this._updateBounds(shape); + } + + _updateBounds(shape) { + const coords = [ + { x: shape.x1, y: shape.y1, z: shape.z1 }, + { x: shape.x2, y: shape.y2, z: shape.z2 } + ]; + + coords.forEach(coord => { + this.bounds.min.x = Math.min(this.bounds.min.x, coord.x); + this.bounds.min.y = Math.min(this.bounds.min.y, coord.y); + this.bounds.min.z = Math.min(this.bounds.min.z, coord.z); + this.bounds.max.x = Math.max(this.bounds.max.x, coord.x); + this.bounds.max.y = Math.max(this.bounds.max.y, coord.y); + this.bounds.max.z = Math.max(this.bounds.max.z, coord.z); + }); + } + + autoScale() { + if (this.shapes.size === 0) return; + + const dx = this.bounds.max.x - this.bounds.min.x; + const dy = this.bounds.max.y - this.bounds.min.y; + const dz = (this.bounds.max.z - this.bounds.min.z) * 5.0; + + if (dx < 1e-6 || dy < 1e-6 || dz < 1e-6) return; + + this.shapes.forEach(shapeList => { + shapeList.forEach(shape => { + shape.x1 = ((shape.x1 - this.bounds.min.x) / dx) * 100.0; + shape.x2 = ((shape.x2 - this.bounds.min.x) / dx) * 100.0; + shape.y1 = ((shape.y1 - this.bounds.min.y) / dy) * 100.0; + shape.y2 = ((shape.y2 - this.bounds.min.y) / dy) * 100.0; + shape.z1 = ((shape.z1 - this.bounds.min.z) / dz) * 100.0; + shape.z2 = ((shape.z2 - this.bounds.min.z) / dz) * 100.0; + }); + }); + + // Update bounds after scaling + this.bounds = { + min: { x: 0, y: 0, z: 0 }, + max: { x: 100, y: 100, z: 100 } + }; + } + + loadFromJSON(jsonData) { + this.clear(); + + if (jsonData.shapes) { + jsonData.shapes.forEach(item => { + const color = item.color || { r: 1, g: 1, b: 1 }; + + switch (item.type) { + case 'Wire': + this.addWire( + item.x1, item.y1, item.z1, + item.x2, item.y2, item.z2, + item.comment || '', + item.shapeClass || 'default', + color + ); + break; + case 'Rect': + this.addRect( + item.x1, item.y1, item.z1, + item.x2, item.y2, item.z2, + item.comment || '', + item.shapeClass || 'default', + color + ); + break; + case 'Via': + this.addVia( + item.x1, item.y1, item.z1, item.z2, + item.comment || '', + item.shapeClass || 'default', + color + ); + break; + } + }); + } + + this.autoScale(); + } + + clear() { + this.shapes.clear(); + this.classVisibility.clear(); + this.classColors.clear(); + this.bounds = { + min: { x: Infinity, y: Infinity, z: Infinity }, + max: { x: -Infinity, y: -Infinity, z: -Infinity } + }; + } + + getShapesByClass(className) { + return this.shapes.get(className) || []; + } + + isClassVisible(className) { + return this.classVisibility.get(className) !== false; + } + + setClassVisibility(className, visible) { + this.classVisibility.set(className, visible); + } + + getClassColor(className) { + return this.classColors.get(className) || { r: 1, g: 1, b: 1 }; + } + + setClassColor(className, color) { + this.classColors.set(className, color); + } + + getAllClasses() { + return Array.from(this.shapes.keys()); + } + + getBounds() { + return this.bounds; + } +} diff --git a/src/vectorization/src/graph/data_manager/layout-viewer/js/main.js b/src/vectorization/src/graph/data_manager/layout-viewer/js/main.js new file mode 100644 index 0000000000000000000000000000000000000000..ecb1e3cc11929b82bd13e24f5a0670430a0f1813 --- /dev/null +++ b/src/vectorization/src/graph/data_manager/layout-viewer/js/main.js @@ -0,0 +1,80 @@ +// Main application initialization +class App { + constructor() { + this.init(); + } + + init() { + const canvas = document.getElementById('canvas'); + this.sceneManager = new SceneManager(canvas); + this.controlsManager = new ControlsManager(this.sceneManager); + + // Add some sample data for demonstration + this.addSampleData(); + + console.log('3D Layout Viewer initialized'); + console.log('Server running at http://localhost:19999'); + } + + addSampleData() { + // Add some sample shapes to demonstrate functionality + const colors = [ + { r: 1, g: 0, b: 0 }, // Red + { r: 0, g: 1, b: 0 }, // Green + { r: 0, g: 0, b: 1 }, // Blue + { r: 1, g: 1, b: 0 }, // Yellow + { r: 1, g: 0, b: 1 }, // Magenta + ]; + + // Add sample wires + for (let i = 0; i < 5; i++) { + this.sceneManager.addWire( + i * 20, 0, 0, + i * 20, 50, 0, + `Sample wire ${i + 1}`, + `Wire_Class_${i + 1}`, + colors[i % colors.length] + ); + } + + // Add sample rectangles + for (let i = 0; i < 3; i++) { + this.sceneManager.addRect( + i * 30, 20, 5, + i * 30 + 15, 35, 5, + `Sample rect ${i + 1}`, + `Rect_Class_${i + 1}`, + colors[i % colors.length] + ); + } + + // Add sample vias + for (let i = 0; i < 4; i++) { + this.sceneManager.addVia( + i * 25, 40, 0, 20, + `Sample via ${i + 1}`, + `Via_Class_${i + 1}`, + colors[i % colors.length] + ); + } + + this.sceneManager.dataManager.autoScale(); + this.sceneManager.resetView(); + this.controlsManager.updateClassTable(); + this.controlsManager.updateGroupsDisplay(); + } +} + +// Initialize the application when the page loads +document.addEventListener('DOMContentLoaded', () => { + new App(); +}); + +// Global error handling +window.addEventListener('error', (e) => { + console.error('Application error:', e.error); +}); + +window.addEventListener('unhandledrejection', (e) => { + console.error('Unhandled promise rejection:', e.reason); +}); diff --git a/src/vectorization/src/graph/data_manager/layout-viewer/js/scene-manager.js b/src/vectorization/src/graph/data_manager/layout-viewer/js/scene-manager.js new file mode 100644 index 0000000000000000000000000000000000000000..2aef10ab0dff5edc52f22fc2e187436136d8629c --- /dev/null +++ b/src/vectorization/src/graph/data_manager/layout-viewer/js/scene-manager.js @@ -0,0 +1,631 @@ +class SceneManager { + constructor(canvas) { + this.canvas = canvas; + this.scene = new THREE.Scene(); + this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000); + this.renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true }); + this.dataManager = new DataManager(); + + this.meshGroups = new Map(); // className -> THREE.Group + this.axesHelper = null; + this.axesVisible = false; + + // Custom mouse controls + this.isMouseDown = false; + this.lastMousePos = { x: 0, y: 0 }; + this.isRotationMode = false; + this.panSpeed = 0.5; + this.rotationSpeed = 1.0; + + // Keyboard state + this.keys = { + ctrl: false + }; + + // Pan state + this.panOffset = { x: 0, y: 0 }; + + this.setupScene(); + this.setupEventListeners(); + this.setupCustomControls(); + } + + setupScene() { + this.scene.background = new THREE.Color(0x262626); + + // Setup renderer + this.renderer.setSize(this.canvas.parentElement.clientWidth, this.canvas.parentElement.clientHeight); + this.renderer.setPixelRatio(window.devicePixelRatio); + this.renderer.shadowMap.enabled = true; + this.renderer.shadowMap.type = THREE.PCFSoftShadowMap; + + // Setup camera with initial view: XY plane at bottom, Z-axis pointing up + this.setupInitialCameraPosition(); + + // Setup lighting + const ambientLight = new THREE.AmbientLight(0xffffff, 0.4); + this.scene.add(ambientLight); + + const directionalLight = new THREE.DirectionalLight(0xffffff, 0.6); + directionalLight.position.set(100, 100, 50); + directionalLight.castShadow = true; + this.scene.add(directionalLight); + + // Create a group for all objects that we want to rotate/pan + this.objectGroup = new THREE.Group(); + this.scene.add(this.objectGroup); + + this.animate(); + } + + setupInitialCameraPosition() { + // Position camera to view XY plane from above at an angle + // XY plane is at the bottom (Z=0), positive Z points up + this.camera.position.set(50, 50, 50); + this.camera.lookAt(0, 0, 0); + + // Set camera up vector to ensure Z is up + this.camera.up.set(0, 0, 1); + this.camera.updateProjectionMatrix(); + } + + calculateOptimalView(bounds) { + // Calculate data dimensions + const sizeX = bounds.max.x - bounds.min.x; + const sizeY = bounds.max.y - bounds.min.y; + const sizeZ = bounds.max.z - bounds.min.z; + + // Find the maximum dimension to determine overall scale + const maxSize = Math.max(sizeX, sizeY, sizeZ); + + // Calculate center point + const center = { + x: (bounds.min.x + bounds.max.x) / 2, + y: (bounds.min.y + bounds.max.y) / 2, + z: (bounds.min.z + bounds.max.z) / 2 + }; + + // Calculate camera distance to fit all data + // Use field of view to determine appropriate distance + const fov = this.camera.fov * Math.PI / 180; // Convert to radians + const aspect = this.camera.aspect; + + // Calculate distance needed to fit the data with some padding + const padding = 1.5; // Add 50% padding around the data + const distance = (maxSize * padding) / (2 * Math.tan(fov / 2)); + + // Position camera at optimal distance with Z-up orientation + // Place camera at an angle to show 3D structure clearly + const cameraOffset = distance * 0.8; + + return { + center, + distance, + cameraOffset, + maxSize, + bounds + }; + } + + updateAxesHelper(bounds) { + // Remove existing axes + if (this.axesHelper) { + this.objectGroup.remove(this.axesHelper); + this.axesHelper = null; + } + + // Create new axes that encompass all data + if (this.axesVisible) { + const sizeX = bounds.max.x - bounds.min.x; + const sizeY = bounds.max.y - bounds.min.y; + const sizeZ = bounds.max.z - bounds.min.z; + + // Make axes slightly larger than data bounds + const axisLength = Math.max(sizeX, sizeY, sizeZ) * 1.2; + + // Create custom axes helper positioned at data origin + this.axesHelper = new THREE.Group(); + + // X-axis (red) + const xGeometry = new THREE.BufferGeometry(); + xGeometry.setAttribute('position', new THREE.BufferAttribute( + new Float32Array([ + bounds.min.x - axisLength * 0.1, 0, 0, + bounds.max.x + axisLength * 0.1, 0, 0 + ]), 3)); + const xMaterial = new THREE.LineBasicMaterial({ color: 0xff0000, linewidth: 3 }); + const xLine = new THREE.Line(xGeometry, xMaterial); + this.axesHelper.add(xLine); + + // Y-axis (green) + const yGeometry = new THREE.BufferGeometry(); + yGeometry.setAttribute('position', new THREE.BufferAttribute( + new Float32Array([ + 0, bounds.min.y - axisLength * 0.1, 0, + 0, bounds.max.y + axisLength * 0.1, 0 + ]), 3)); + const yMaterial = new THREE.LineBasicMaterial({ color: 0x00ff00, linewidth: 3 }); + const yLine = new THREE.Line(yGeometry, yMaterial); + this.axesHelper.add(yLine); + + // Z-axis (blue) + const zGeometry = new THREE.BufferGeometry(); + zGeometry.setAttribute('position', new THREE.BufferAttribute( + new Float32Array([ + 0, 0, bounds.min.z - axisLength * 0.1, + 0, 0, bounds.max.z + axisLength * 0.1 + ]), 3)); + const zMaterial = new THREE.LineBasicMaterial({ color: 0x0000ff, linewidth: 3 }); + const zLine = new THREE.Line(zGeometry, zMaterial); + this.axesHelper.add(zLine); + + this.objectGroup.add(this.axesHelper); + } + } + + setupEventListeners() { + window.addEventListener('resize', () => this.onWindowResize()); + + // Keyboard events for Ctrl key detection + window.addEventListener('keydown', (event) => { + if (event.key === 'Control' || event.ctrlKey) { + this.keys.ctrl = true; + } + }); + + window.addEventListener('keyup', (event) => { + if (event.key === 'Control' || !event.ctrlKey) { + this.keys.ctrl = false; + } + }); + + // Handle focus loss to reset key states + window.addEventListener('blur', () => { + this.keys.ctrl = false; + }); + + // Mouse events for tooltip + this.raycaster = new THREE.Raycaster(); + this.mouse = new THREE.Vector2(); + + this.canvas.addEventListener('mousemove', (event) => this.onMouseMove(event)); + } + + setupCustomControls() { + this.canvas.addEventListener('mousedown', (event) => this.onMouseDown(event)); + this.canvas.addEventListener('mousemove', (event) => this.onMouseMoveCustom(event)); + this.canvas.addEventListener('mouseup', (event) => this.onMouseUp(event)); + this.canvas.addEventListener('mouseleave', (event) => this.onMouseUp(event)); // Handle mouse leaving canvas + this.canvas.addEventListener('wheel', (event) => this.onMouseWheel(event)); + + // Prevent context menu + this.canvas.addEventListener('contextmenu', (event) => event.preventDefault()); + } + + onMouseDown(event) { + // Skip if clicking on control panel + if (event.clientX < 300) return; + + this.isMouseDown = true; + const rect = this.canvas.getBoundingClientRect(); + this.lastMousePos = { + x: event.clientX - rect.left, + y: event.clientY - rect.top + }; + + this.canvas.style.cursor = this.isRotationMode ? 'grabbing' : 'move'; + } + + onMouseMoveCustom(event) { + // Skip if clicking on control panel + if (event.clientX < 300) return; + + const rect = this.canvas.getBoundingClientRect(); + const currentPos = { + x: event.clientX - rect.left, + y: event.clientY - rect.top + }; + + if (this.isMouseDown) { + const deltaX = currentPos.x - this.lastMousePos.x; + const deltaY = currentPos.y - this.lastMousePos.y; + + if (this.isRotationMode) { + // Rotation mode - check for Ctrl key + if (this.keys.ctrl) { + this.rotateSceneWorldZAxis(deltaX); + } else { + this.rotateScene(deltaX, deltaY); + } + } else { + // Pan mode - reversed direction + this.panScene(deltaX, deltaY); + } + } + + this.lastMousePos = currentPos; + } + + onMouseUp(event) { + if (!this.isMouseDown) return; + + this.isMouseDown = false; + this.canvas.style.cursor = 'default'; + } + + onMouseWheel(event) { + // Skip if over control panel + if (event.clientX < 300) return; + + event.preventDefault(); + + const zoomFactor = event.deltaY > 0 ? 1.1 : 0.9; + this.camera.position.multiplyScalar(zoomFactor); + } + + rotateScene(deltaX, deltaY) { + // More intuitive rotation that follows mouse movement + // The scene rotates as if you're grabbing and turning a physical object + + // Get the camera's current view direction and up vector + const cameraDirection = new THREE.Vector3(); + this.camera.getWorldDirection(cameraDirection); + + // Calculate rotation axes relative to camera view + const cameraUp = this.camera.up.clone(); + const cameraRight = new THREE.Vector3().crossVectors(cameraUp, cameraDirection).normalize(); + + // Horizontal mouse movement (deltaX) rotates around the world Z-axis (since Z is up) + // This makes left/right mouse movement rotate the object left/right as expected + const zRotation = -deltaX * 0.01 * this.rotationSpeed; + this.objectGroup.rotateOnWorldAxis(new THREE.Vector3(0, 0, 1), zRotation); + + // Vertical mouse movement (deltaY) rotates around the camera's right vector + // This makes up/down mouse movement tilt the object up/down as expected + const xRotation = -deltaY * 0.01 * this.rotationSpeed; + + // Transform the camera's right vector to world space for consistent rotation + const worldRight = cameraRight.clone(); + this.objectGroup.rotateOnWorldAxis(worldRight, xRotation); + } + + rotateSceneWorldZAxis(deltaX) { + // Z-axis only rotation around the world coordinate system Z-axis + // This rotates around the absolute Z-axis of the coordinate system, + // not the viewport/camera Z-axis. Positive deltaX rotates counterclockwise + // when viewed from above (looking down the positive Z-axis). + const zRotation = -deltaX * 0.01 * this.rotationSpeed; + + // Use the world Z-axis vector explicitly to ensure strict Z-axis rotation + const worldZAxis = new THREE.Vector3(0, 0, 1); + this.objectGroup.rotateOnWorldAxis(worldZAxis, zRotation); + } + + panScene(deltaX, deltaY) { + // Convert screen space movement to world space + // Reversed direction: positive deltaX moves scene left, positive deltaY moves scene down + + // Get camera's right and up vectors + const cameraMatrix = this.camera.matrixWorld.clone(); + const right = new THREE.Vector3(); + const up = new THREE.Vector3(); + + right.setFromMatrixColumn(cameraMatrix, 0); // X column + up.setFromMatrixColumn(cameraMatrix, 1); // Y column + + // Calculate pan distance based on camera distance + const distance = this.camera.position.length(); + const panScale = distance * 0.001 * this.panSpeed; + + // Apply panning with reversed direction + const panVector = new THREE.Vector3(); + panVector.addScaledVector(right, deltaX * panScale); // Reversed: removed minus sign + panVector.addScaledVector(up, -deltaY * panScale); // Reversed: changed plus to minus + + this.objectGroup.position.add(panVector); + } + + setRotationMode(enabled) { + this.isRotationMode = enabled; + this.canvas.style.cursor = 'default'; + } + + onWindowResize() { + const container = this.canvas.parentElement; + const width = container.clientWidth; + const height = container.clientHeight; + + this.camera.aspect = width / height; + this.camera.updateProjectionMatrix(); + this.renderer.setSize(width, height); + } + + onMouseMove(event) { + // This is for tooltip functionality only + const rect = this.canvas.getBoundingClientRect(); + this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; + this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; + + this.raycaster.setFromCamera(this.mouse, this.camera); + + const tooltip = document.getElementById('tooltip'); + const intersects = this.raycaster.intersectObjects(this.scene.children, true); + + if (intersects.length > 0) { + const intersect = intersects[0]; + const userData = intersect.object.userData; + + // Only show tooltip if the object has a comment AND its class is visible + if (userData.comment && userData.shapeClass && this.dataManager.isClassVisible(userData.shapeClass)) { + tooltip.style.display = 'block'; + tooltip.style.left = event.clientX + 10 + 'px'; + tooltip.style.top = event.clientY + 10 + 'px'; + tooltip.textContent = userData.comment; + } else { + tooltip.style.display = 'none'; + } + } else { + tooltip.style.display = 'none'; + } + } + + animate() { + requestAnimationFrame(() => this.animate()); + this.renderer.render(this.scene, this.camera); + } + + addWire(x1, y1, z1, x2, y2, z2, comment, shapeClass, color) { + this.dataManager.addWire(x1, y1, z1, x2, y2, z2, comment, shapeClass, color); + this.createWireMesh(x1, y1, z1, x2, y2, z2, comment, shapeClass, color); + } + + addRect(x1, y1, z1, x2, y2, z2, comment, shapeClass, color) { + this.dataManager.addRect(x1, y1, z1, x2, y2, z2, comment, shapeClass, color); + this.createRectMesh(x1, y1, z1, x2, y2, z2, comment, shapeClass, color); + } + + addVia(x, y, z1, z2, comment, shapeClass, color) { + this.dataManager.addVia(x, y, z1, z2, comment, shapeClass, color); + this.createViaMesh(x, y, z1, z2, comment, shapeClass, color); + } + + createWireMesh(x1, y1, z1, x2, y2, z2, comment, shapeClass, color) { + // Calculate wire direction and length + const direction = new THREE.Vector3(x2 - x1, y2 - y1, z2 - z1); + const length = direction.length(); + direction.normalize(); + + // Create a cylindrical geometry for the wire with visible thickness + const wireRadius = Math.max(0.1, length * 0.002); // Dynamic radius based on wire length + const geometry = new THREE.CylinderGeometry(wireRadius, wireRadius, length, 8); + + const material = new THREE.MeshBasicMaterial({ + color: new THREE.Color(color.r, color.g, color.b), + transparent: color.a !== undefined, + opacity: color.a !== undefined ? color.a : 1.0 + }); + + const mesh = new THREE.Mesh(geometry, material); + + // Position the mesh at the midpoint of the wire + const midpoint = new THREE.Vector3( + (x1 + x2) / 2, + (y1 + y2) / 2, + (z1 + z2) / 2 + ); + mesh.position.copy(midpoint); + + // Align the cylinder with the wire direction + const up = new THREE.Vector3(0, 1, 0); + const quaternion = new THREE.Quaternion(); + quaternion.setFromUnitVectors(up, direction); + mesh.setRotationFromQuaternion(quaternion); + + mesh.userData = { comment, shapeClass, type: 'Wire' }; + + this.addToGroup(mesh, shapeClass); + } + + createRectMesh(x1, y1, z1, x2, y2, z2, comment, shapeClass, color) { + const width = Math.abs(x2 - x1); + const height = Math.abs(y2 - y1); + const centerX = (x1 + x2) / 2; + const centerY = (y1 + y2) / 2; + + const geometry = new THREE.PlaneGeometry(width, height); + const material = new THREE.MeshBasicMaterial({ + color: new THREE.Color(color.r, color.g, color.b), + side: THREE.DoubleSide, + transparent: true, + opacity: color.a !== undefined ? color.a : 0.85 + }); + + const mesh = new THREE.Mesh(geometry, material); + mesh.position.set(centerX, centerY, z1); + mesh.userData = { comment, shapeClass, type: 'Rect' }; + + this.addToGroup(mesh, shapeClass); + } + + createViaMesh(x, y, z1, z2, comment, shapeClass, color) { + // Calculate via direction and length + const length = Math.abs(z2 - z1); + const centerZ = (z1 + z2) / 2; + + // Create a cylindrical geometry for the via with half the width of wire + // Wire radius is: Math.max(0.1, length * 0.002) + // Via radius is half of that + const viaRadius = Math.max(0.05, length * 0.001); // Half of wire radius + const geometry = new THREE.CylinderGeometry(viaRadius, viaRadius, length, 8); + + const material = new THREE.MeshBasicMaterial({ + color: new THREE.Color(color.r, color.g, color.b), + transparent: color.a !== undefined, + opacity: color.a !== undefined ? color.a : 1.0 + }); + + const mesh = new THREE.Mesh(geometry, material); + + // Position the mesh at the center point + mesh.position.set(x, y, centerZ); + + // Rotate to align with Z-axis (cylinder default is Y-axis) + mesh.rotateX(Math.PI / 2); + + mesh.userData = { comment, shapeClass, type: 'Via' }; + + this.addToGroup(mesh, shapeClass); + } + + addToGroup(mesh, shapeClass) { + if (!this.meshGroups.has(shapeClass)) { + const group = new THREE.Group(); + group.name = shapeClass; + this.meshGroups.set(shapeClass, group); + this.objectGroup.add(group); // Add to objectGroup instead of scene + } + + this.meshGroups.get(shapeClass).add(mesh); + } + + setClassVisibility(className, visible) { + this.dataManager.setClassVisibility(className, visible); + const group = this.meshGroups.get(className); + if (group) { + group.visible = visible; + } + } + + setClassColor(className, color) { + this.dataManager.setClassColor(className, color); + const group = this.meshGroups.get(className); + if (group) { + group.children.forEach(child => { + if (child.material) { + child.material.color.setRGB(color.r, color.g, color.b); + + // Handle alpha transparency + if (color.a !== undefined) { + child.material.transparent = true; + child.material.opacity = color.a; + } else { + child.material.transparent = false; + child.material.opacity = 1.0; + } + + // Update material to reflect changes + child.material.needsUpdate = true; + } + }); + } + } + + showAxes(show = true) { + this.axesVisible = show; + + // Update axes based on current data bounds + const bounds = this.dataManager.getBounds(); + if (bounds.min.x !== Infinity) { + this.updateAxesHelper(bounds); + } else if (!show && this.axesHelper) { + // Remove axes if no data and hiding + this.objectGroup.remove(this.axesHelper); + this.axesHelper = null; + } + } + + toggleAxes() { + this.showAxes(!this.axesVisible); + } + + resetView() { + // Reset object group transform + this.objectGroup.position.set(0, 0, 0); + this.objectGroup.rotation.set(0, 0, 0); + + // Reset camera to optimal position based on data bounds + const bounds = this.dataManager.getBounds(); + if (bounds.min.x === Infinity) { + // No data, use default position with Z-up + this.setupInitialCameraPosition(); + } else { + const viewInfo = this.calculateOptimalView(bounds); + + // Position camera at optimal distance with Z-up orientation + this.camera.position.set( + viewInfo.center.x + viewInfo.cameraOffset, + viewInfo.center.y + viewInfo.cameraOffset, + viewInfo.center.z + viewInfo.cameraOffset + ); + + this.camera.lookAt(viewInfo.center.x, viewInfo.center.y, viewInfo.center.z); + + // Ensure Z is up + this.camera.up.set(0, 0, 1); + this.camera.updateProjectionMatrix(); + + // Update axes to match data bounds + if (this.axesVisible) { + this.updateAxesHelper(bounds); + } + } + } + + clearScene() { + // Remove all mesh groups + this.meshGroups.forEach(group => { + this.objectGroup.remove(group); + }); + this.meshGroups.clear(); + + // Remove axes + if (this.axesHelper) { + this.objectGroup.remove(this.axesHelper); + this.axesHelper = null; + } + + // Clear data + this.dataManager.clear(); + } + + loadFromJSON(jsonData) { + this.clearScene(); + this.dataManager.loadFromJSON(jsonData); + this.rebuildScene(); + this.resetView(); + } + + rebuildScene() { + this.dataManager.shapes.forEach((shapes, className) => { + const color = this.dataManager.getClassColor(className); + shapes.forEach(shape => { + switch (shape.type) { + case 'Wire': + this.createWireMesh( + shape.x1, shape.y1, shape.z1, + shape.x2, shape.y2, shape.z2, + shape.comment, shape.shapeClass, color + ); + break; + case 'Rect': + this.createRectMesh( + shape.x1, shape.y1, shape.z1, + shape.x2, shape.y2, shape.z2, + shape.comment, shape.shapeClass, color + ); + break; + case 'Via': + this.createViaMesh( + shape.x1, shape.y1, shape.z1, shape.z2, + shape.comment, shape.shapeClass, color + ); + break; + } + }); + }); + } + + getDataManager() { + return this.dataManager; + } +} diff --git a/src/vectorization/src/graph/data_manager/layout-viewer/package-lock.json b/src/vectorization/src/graph/data_manager/layout-viewer/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..420efbf6c584ee0bc35e38c6d5a486d4f586b066 --- /dev/null +++ b/src/vectorization/src/graph/data_manager/layout-viewer/package-lock.json @@ -0,0 +1,917 @@ +{ + "name": "web-layout-viewer", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "web-layout-viewer", + "version": "1.0.0", + "dependencies": { + "express": "^4.18.2", + "multer": "^1.4.5-lts.1" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/multer": { + "version": "1.4.5-lts.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz", + "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==", + "deprecated": "Multer 1.x is impacted by a number of vulnerabilities, which have been patched in 2.x. You should upgrade to the latest 2.x version.", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/src/vectorization/src/graph/data_manager/layout-viewer/package.json b/src/vectorization/src/graph/data_manager/layout-viewer/package.json new file mode 100644 index 0000000000000000000000000000000000000000..f29498f8c1e88539dbfac95468d9a4a57f023542 --- /dev/null +++ b/src/vectorization/src/graph/data_manager/layout-viewer/package.json @@ -0,0 +1,13 @@ +{ + "name": "web-layout-viewer", + "version": "1.0.0", + "description": "3D Layout Visualization Tool", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "express": "^4.18.2", + "multer": "^1.4.5-lts.1" + } +} \ No newline at end of file diff --git a/src/analysis/api/CMakeLists.txt b/src/vectorization/src/graph/data_manager/layout-viewer/sample_data.json similarity index 100% rename from src/analysis/api/CMakeLists.txt rename to src/vectorization/src/graph/data_manager/layout-viewer/sample_data.json diff --git a/src/vectorization/src/graph/data_manager/layout-viewer/server.js b/src/vectorization/src/graph/data_manager/layout-viewer/server.js new file mode 100644 index 0000000000000000000000000000000000000000..05d39c7bffbcbeccce2c492d048062986a8226e2 --- /dev/null +++ b/src/vectorization/src/graph/data_manager/layout-viewer/server.js @@ -0,0 +1,46 @@ +const express = require('express'); +const multer = require('multer'); +const path = require('path'); +const fs = require('fs'); + +const app = express(); +const PORT = 19999; + +// Serve static files +app.use(express.static(__dirname)); + +// Configure multer for file uploads +const upload = multer({ + dest: 'uploads/', + fileFilter: (req, file, cb) => { + if (file.mimetype === 'application/json') { + cb(null, true); + } else { + cb(new Error('Only JSON files are allowed!'), false); + } + } +}); + +// Upload endpoint +app.post('/upload', upload.single('jsonFile'), (req, res) => { + try { + if (!req.file) { + return res.status(400).json({ error: 'No file uploaded' }); + } + + const fileContent = fs.readFileSync(req.file.path, 'utf8'); + const jsonData = JSON.parse(fileContent); + + // Clean up uploaded file + fs.unlinkSync(req.file.path); + + res.json({ success: true, data: jsonData }); + } catch (error) { + console.error('Error processing upload:', error); + res.status(500).json({ error: 'Failed to process file' }); + } +}); + +app.listen(PORT, () => { + console.log(`Server running at http://localhost:${PORT}`); +}); diff --git a/src/analysis/config/CMakeLists.txt b/src/vectorization/src/graph/data_manager/layout-viewer/test.html similarity index 100% rename from src/analysis/config/CMakeLists.txt rename to src/vectorization/src/graph/data_manager/layout-viewer/test.html diff --git a/src/vectorization/src/graph/data_manager/vec_graph_check.cc b/src/vectorization/src/graph/data_manager/vec_graph_check.cc new file mode 100644 index 0000000000000000000000000000000000000000..c30e6c7386e15bc2160533941bec8f00d57cb594 --- /dev/null +++ b/src/vectorization/src/graph/data_manager/vec_graph_check.cc @@ -0,0 +1,529 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file vec_layout_check.cc + * @author Dawn Li (dawnli619215645@gmail.com) + * @version 1.0 + * @date 2024-11-15 + * @brief Check layout data (connectivity of nets, wires, etc.), and provide interfaces for graph construction. + */ +#include "vec_graph_check.hh" + +#include +#include +#include +#include +#include +#include + +#include "log/Log.hh" +#include "omp.h" +#include "usage.hh" +namespace ivec { + +bool GraphCheckerBase::isConnectivity(const Graph& graph) const +{ + std::vector component(boost::num_vertices(graph)); + int num_components = boost::connected_components(graph, &component[0]); + + // If there's only one connected component, the net is fully connected + return (num_components == 1); +} + +void GraphCheckerBase::writeToDot(const Graph& graph, const std::string& path) const +{ + std::ofstream file(path); + boost::write_graphviz(file, graph, [&](std::ostream& out, const Graph::vertex_descriptor& v) { + out << "[x=" << std::to_string(graph[v].x) << ", y=" << std::to_string(graph[v].y) << ", layer_id=" << std::to_string(graph[v].layer_id) + << ", pin_id=" << std::to_string(graph[v].pin_id) << "]"; + }); +} + +void GraphCheckerBase::writeToPy(VecNet& net, const std::string& path) const +{ + // Write the wire line to a Python file for plotting in 3D space (x, y, layer_id) using Plotly + std::ofstream file(path); + file << "import plotly.graph_objects as go\n"; + file << "\n"; + file << "# Create a Plotly Figure\n"; + file << "fig = go.Figure()\n"; + file << "\n"; + + // Add data for each wire and path + auto& wires = net.get_wires(); + for (auto& wire : wires) { + auto& paths = wire.get_paths(); + for (auto& path : paths) { + auto* start = path.first; + auto* end = path.second; + + // Add a trace for each path + file << "fig.add_trace(go.Scatter3d(\n"; + file << " x=[" << start->get_x() << ", " << end->get_x() << "],\n"; + file << " y=[" << start->get_y() << ", " << end->get_y() << "],\n"; + file << " z=[" << start->get_layer_id() << ", " << end->get_layer_id() << "],\n"; + file << " mode='lines',\n"; + file << " line=dict(color='rgb(" << (50 + end->get_layer_id() * 20) % 256 << "," << (100 + end->get_layer_id() * 30) % 256 << "," + << (150 + end->get_layer_id() * 40) % 256 << ")', width=4),\n"; + file << "))\n"; + } + } + + // Set up the layout with axis labels and title + file << "\n"; + file << "fig.update_layout(\n"; + file << " scene=dict(\n"; + file << " xaxis_title='X',\n"; + file << " yaxis_title='Y',\n"; + file << " zaxis_title='Layer ID'\n"; + file << " ),\n"; + file << " title='Net " << net.get_net_id() << "'\n"; + file << ")\n"; + file << "\n"; + + // Show the plot + file << "fig.show()\n"; +} + +void GraphCheckerBase::writeToPy(const Graph& graph, VecNet& net, const std::string& path, const bool& mark_break, + const bool& mark_pin_id) const +{ + // get all + auto& wires = net.get_wires(); + // build a map for get wire by (x1,y1,layer_id1) and (x2,y2,layer_id2) + struct WireKey + { + int64_t x1; + int64_t y1; + int layer_id1; + int pin_id1; + int64_t x2; + int64_t y2; + int layer_id2; + int pin_id2; + bool operator==(const WireKey& other) const + { + return x1 == other.x1 && y1 == other.y1 && layer_id1 == other.layer_id1 && pin_id1 == other.pin_id1 && x2 == other.x2 + && y2 == other.y2 && layer_id2 == other.layer_id2 && pin_id2 == other.pin_id2; + } + }; + struct WireKeyHash + { + std::size_t operator()(const WireKey& key) const + { + return (std::hash()(key.x1) ^ std::hash()(key.y1) ^ std::hash()(key.layer_id1) ^ std::hash()(key.pin_id1) + ^ std::hash()(key.x2) ^ std::hash()(key.y2) ^ std::hash()(key.layer_id2) ^ std::hash()(key.pin_id2)); + } + }; + std::unordered_map wire_map; + for (auto& wire : wires) { + auto connected_nodes = wire.get_connected_nodes(); + auto* start = connected_nodes.first; + auto* end = connected_nodes.second; + WireKey key = {start->get_x(), start->get_y(), start->get_layer_id(), start->get_node_data()->get_pin_id(), + end->get_x(), end->get_y(), end->get_layer_id(), end->get_node_data()->get_pin_id()}; + wire_map[key] = wire; + WireKey key_reverse = {end->get_x(), end->get_y(), end->get_layer_id(), end->get_node_data()->get_pin_id(), + start->get_x(), start->get_y(), start->get_layer_id(), start->get_node_data()->get_pin_id()}; + wire_map[key_reverse] = wire; + } + + // Write the wire line to a Python file for plotting in 3D space (x, y, layer_id) using Plotly + std::ofstream file(path); + file << "import plotly.graph_objects as go\n"; + file << "import matplotlib.cm as cm\n"; + file << "\n"; + file << "# Create a Plotly Figure\n"; + file << "fig = go.Figure()\n"; + file << "\n"; + + // for each component, plot the subgraph edges' label (x,y,layer_id), use the same color for the same component + std::vector component(boost::num_vertices(graph)); + size_t num_components = boost::connected_components(graph, &component[0]); + file << "colors = [f'rgb{cm.tab10(i)[:3]}' for i in range(" << num_components << ")]\n"; + for (size_t i = 0; i < num_components; ++i) { + file << "# Component " << i << "\n"; + // for each wire, plot the wire with the same color + size_t wire_idx = 0; + for (auto e : boost::make_iterator_range(boost::edges(graph))) { + auto u = boost::source(e, graph); + auto v = boost::target(e, graph); + if (component[u] == i && component[v] == i) { + // file << "fig.add_trace(go.Scatter3d(\n"; + // file << " x=[" << graph[u].x << ", " << graph[v].x << "],\n"; + // file << " y=[" << graph[u].y << ", " << graph[v].y << "],\n"; + // file << " z=[" << graph[u].layer_id << ", " << graph[v].layer_id << "],\n"; + // file << " mode='lines',\n"; + // file << " line=dict(color=colors[" << i << "], width=4),\n"; + // file << " name='Component " << i << ", Wire " << wire_idx++ << "'\n"; + // file << "))\n"; + auto wire = wire_map[{graph[u].x, graph[u].y, graph[u].layer_id, graph[u].pin_id, graph[v].x, graph[v].y, graph[v].layer_id, + graph[v].pin_id}]; + size_t path_idx = 0; + for (auto& path : wire.get_paths()) { + auto* start = path.first; + auto* end = path.second; + file << "fig.add_trace(go.Scatter3d(\n"; + file << " x=[" << start->get_x() << ", " << end->get_x() << "],\n"; + file << " y=[" << start->get_y() << ", " << end->get_y() << "],\n"; + file << " z=[" << start->get_layer_id() << ", " << end->get_layer_id() << "],\n"; + file << " mode='lines',\n"; + file << " line=dict(color=colors[" << i << "], width=4),\n"; + file << " name='Component " << i << ", Wire " << wire_idx << ", Path " << path_idx++ << "'\n"; + file << "))\n"; + } + wire_idx++; + } + } + } + + // plot the nodes which degree is 1, plot with 'x' marker + if (mark_break) { + for (auto v : boost::make_iterator_range(boost::vertices(graph))) { + if (boost::degree(v, graph) == 1) { + file << "fig.add_trace(go.Scatter3d(\n"; + file << " x=[" << graph[v].x << "],\n"; + file << " y=[" << graph[v].y << "],\n"; + file << " z=[" << graph[v].layer_id << "],\n"; + file << " mode='markers',\n"; + file << " marker=dict(\n"; + file << " size=3,\n"; + file << " symbol='x',\n"; + file << " color='red'\n"; + file << " )\n"; + file << "))\n"; + } + } + } + + // plot the nodes with pin_id, plot with text + if (mark_pin_id) { + for (auto v : boost::make_iterator_range(boost::vertices(graph))) { + if (graph[v].pin_id != -1) { + file << "fig.add_trace(go.Scatter3d(\n"; + file << " x=[" << graph[v].x << "],\n"; + file << " y=[" << graph[v].y << "],\n"; + file << " z=[" << graph[v].layer_id << "],\n"; + file << " mode='text',\n"; + file << " text=['" << graph[v].pin_id << "'],\n"; + file << " textposition='top center',\n"; + file << " textfont=dict(\n"; + file << " size=12,\n"; + file << " color='black'\n"; + file << " )\n"; + file << "))\n"; + } + } + } + + // Set up the layout with axis labels and title + file << "\n"; + file << "fig.update_layout(\n"; + file << " scene=dict(\n"; + file << " xaxis_title='X',\n"; + file << " yaxis_title='Y',\n"; + file << " zaxis_title='Layer ID'\n"; + file << " ),\n"; + file << " title='Net " << net.get_net_id() << "'\n"; + file << ")\n"; + file << "\n"; + + // Show the plot + file << "fig.show()\n"; +} + +bool VecNetChecker::isLocalConnectivity(VecNet& net) const +{ + /// ignore net if pin number < 2 + if (net.get_pin_ids().size() < 2 || net.get_wires().empty()) { + return true; + } + + auto& wires = net.get_wires(); + // 1. Check wire inner connectivity + for (auto& wire : wires) { + if (!isLocalConnectivity(wire)) { + return false; + } + } + + // 2. Convert the net to a graph + auto graph = convertToGraph(net); + + // 3. Check if the entire graph is connected + return GraphCheckerBase::isConnectivity(graph); +} + +bool VecNetChecker::isLocalConnectivity(VecNetWire& wire) const +{ + std::vector> paths = wire.get_paths(); + auto is_same_xy = [](VecNode* node1, VecNode* node2) { return node1->get_x() == node2->get_x() && node1->get_y() == node2->get_y(); }; + if (paths.empty()) { + return false; + } + if (paths.size() == 1) { + auto* front = paths[0].first; + auto* back = paths[0].second; + // avoid empty pointer + if (!front || !back) { + return false; + } + if (front->get_layer_id() == back->get_layer_id()) { + return front->get_x() == back->get_x() || front->get_y() == back->get_y(); + } + return is_same_xy(front, back); + } + for (size_t i = 0; i < paths.size() - 1; ++i) { + auto* front = paths[i].second; + auto* back = paths[i + 1].first; + // avoid empty pointer + if (!front || !back) { + return false; + } + if (!is_same_xy(front, back)) { + return false; + } + } + auto connect_nodes = wire.get_connected_nodes(); + auto* front = connect_nodes.first; + auto* back = connect_nodes.second; + if (front->get_layer_id() != back->get_layer_id()) { + // check is via + return is_same_xy(front, back); + } + // check is wire (front's x,y != back's x,y) + return !is_same_xy(front, back); +} +Graph VecNetChecker::convertToGraph(VecNet& net) const +{ + // 1. Create a graph based on the net + // Map to assign unique IDs to connection points + std::unordered_map, size_t, boost::hash>> node_to_id; + size_t next_id = 0; + auto& wires = net.get_wires(); + // First pass: Assign unique IDs to each connection point + for (auto& wire : wires) { + auto& connected_nodes = wire.get_connected_nodes(); + auto* start = connected_nodes.first; + auto* end = connected_nodes.second; + + // Create keys based on (x, y, layer_id) + auto start_key = std::make_tuple(start->get_x(), start->get_y(), start->get_layer_id()); + auto end_key = std::make_tuple(end->get_x(), end->get_y(), end->get_layer_id()); + + // Assign unique ID if not already assigned + if (!node_to_id.contains(start_key)) { + node_to_id[start_key] = next_id++; + } + if (!node_to_id.contains(end_key)) { + node_to_id[end_key] = next_id++; + } + } + + // Create a graph with the number of unique connection points as vertices + Graph graph(next_id); + std::unordered_map edge_to_wire; + + // Second pass: Add edges between connection points based on wires + for (auto& wire : wires) { + auto& connected_nodes = wire.get_connected_nodes(); + auto* start = connected_nodes.first; + auto* end = connected_nodes.second; + + auto start_key = std::make_tuple(start->get_x(), start->get_y(), start->get_layer_id()); + auto end_key = std::make_tuple(end->get_x(), end->get_y(), end->get_layer_id()); + + auto start_id = node_to_id[start_key]; + auto end_id = node_to_id[end_key]; + + auto start_vertex = boost::vertex(start_id, graph); + graph[start_vertex].x = start->get_x(); + graph[start_vertex].y = start->get_y(); + graph[start_vertex].layer_id = start->get_layer_id(); + graph[start_vertex].pin_id = start->get_node_data()->get_pin_id(); + + auto end_vertex = boost::vertex(end_id, graph); + graph[end_vertex].x = end->get_x(); + graph[end_vertex].y = end->get_y(); + graph[end_vertex].layer_id = end->get_layer_id(); + graph[end_vertex].pin_id = end->get_node_data()->get_pin_id(); + + auto [edge, inserted] = boost::add_edge(start_id, end_id, graph); + + edge_to_wire[edge] = wire; + } + + // 2. Remove redundant components, if have one component contains all pins, remove all other components (and correspondingly wires) + // Get all pins + auto& pin_ids = net.get_pin_ids(); + std::sort(pin_ids.begin(), pin_ids.end()); + + // Get all components + std::vector component(boost::num_vertices(graph)); + int num_components = boost::connected_components(graph, &component[0]); + + // Try to find the component containing all pins + int desired_component = -1; + for (int component_id = 0; component_id < num_components; ++component_id) { + std::unordered_set pins_in_component; + for (auto v : boost::make_iterator_range(boost::vertices(graph))) { + if (component[v] == component_id) { + auto pin_id = graph[v].pin_id; + if (pin_id != -1) { // pin node + pins_in_component.insert(pin_id); + } + } + } + auto pins_in_component_vec = std::vector(pins_in_component.begin(), pins_in_component.end()); + std::sort(pins_in_component_vec.begin(), pins_in_component_vec.end()); + + if (pins_in_component_vec == pin_ids) { + desired_component = component_id; + break; + } + } + if (desired_component == -1) { + // Not fonud + return graph; + } + + // Remove all other components + std::vector vertices_to_remove; + for (int component_id = 0; component_id < num_components; ++component_id) { + if (component_id != desired_component) { + for (auto v : boost::make_iterator_range(boost::vertices(graph))) { + if (component[v] == component_id) { + vertices_to_remove.push_back(v); + } + } + } + } + + // Update the component's correspondingly wires + std::vector updated_wires; + for (auto e : boost::make_iterator_range(boost::edges(graph))) { + if (component[boost::source(e, graph)] == desired_component) { + auto wire = edge_to_wire[e]; + updated_wires.push_back(wire); + } + } + + std::sort(vertices_to_remove.begin(), vertices_to_remove.end(), [&](const Vertex a, const Vertex b) { return a > b; }); + for (auto v : vertices_to_remove) { + boost::clear_vertex(v, graph); + boost::remove_vertex(v, graph); + } + + wires = updated_wires; + return graph; +} +void VecNetChecker::writeToDot(const Graph& graph, const std::string& path) const +{ + GraphCheckerBase::writeToDot(graph, path); +} +void VecNetChecker::writeToPy(const Graph& graph, VecNet& net, const std::string& path, const bool& mark_break, + const bool& mark_pin_id) const +{ + GraphCheckerBase::writeToPy(graph, net, path, mark_break, mark_pin_id); +} +bool VecLayoutChecker::checkLayout(std::map net_map) +{ + int success_num = 0; + int total = 0; + auto checker = VecNetChecker(); + for (auto& [net_id, net] : net_map) { + if (checker.isLocalConnectivity(net)) { + success_num++; + } else { + LOG_ERROR << "Net " << net.get_net_id() << " is not locally connected."; + // debug + // auto graph = checker.convertToGraph(net); + // GraphCheckerBase::writeToPy(graph, net, "/home/liweiguo/temp/file/net_" + std::to_string(net.get_net_id()) + ".py"); + } + total++; + } + + LOG_INFO << "Net connected succuss ratio : " << success_num << " / " << total; + return success_num == total; +} + +void VecLayoutChecker::checkPinConnection(std::map net_map) +{ + ieda::Stats stats; + + LOG_INFO << "Vectorization check pin connections for routing layer start..."; + + omp_lock_t lck; + omp_init_lock(&lck); + + int connected_num = 0; + + // for (auto& [net_id, net] : net_map) { + // #pragma omp parallel for schedule(dynamic) + for (int i = 0; i < (int) net_map.size(); ++i) { + auto it = net_map.begin(); + std::advance(it, i); + auto& net_id = it->first; + auto& net = it->second; + auto& pin_ids = net.get_pin_ids(); + auto& wires = net.get_wires(); + if (wires.size() <= 0) { + continue; + } + + std::set count_pins = std::set(pin_ids.begin(), pin_ids.end()); + bool b_io = false; + + for (auto& wire : wires) { + auto& [node1, node2] = wire.get_connected_nodes(); + if (node1->get_node_data()->get_pin_id() != -1) { + count_pins.erase(node1->get_node_data()->get_pin_id()); + if (node1->get_node_data()->is_io()) { + b_io = true; + } + } + if (node2->get_node_data()->get_pin_id() != -1) { + count_pins.erase(node2->get_node_data()->get_pin_id()); + if (node2->get_node_data()->is_io()) { + b_io = true; + } + } + } + + if (count_pins.size() > 0) { + for (auto pin_id : count_pins) { + LOG_INFO << "disconnected pin : " << pin_id; + } + + if (b_io) { + LOG_INFO << "has io... "; + } + LOG_INFO << "net " << net_id << " reconnect : " << count_pins.size(); + } else { + LOG_INFO << "net connected " << net_id; + connected_num++; + } + } + + LOG_INFO << "net reconnect ratio " << connected_num << " / " << net_map.size(); + + omp_destroy_lock(&lck); + + LOG_INFO << "Vectorization check pin connections for routing layer end..."; +} + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/graph/data_manager/vec_graph_check.hh b/src/vectorization/src/graph/data_manager/vec_graph_check.hh new file mode 100644 index 0000000000000000000000000000000000000000..b5f90f3bec78becd96a32e31b4bb76d4bab8d02c --- /dev/null +++ b/src/vectorization/src/graph/data_manager/vec_graph_check.hh @@ -0,0 +1,99 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file vec_layout_check.hh + * @author Dawn Li (dawnli619215645@gmail.com) + * @version 1.0 + * @date 2024-11-15 + * @brief Check layout data (connectivity of nets, wires, etc.), and provide interfaces for graph construction. + */ + +#pragma once + +#include + +#include "vec_net.h" +namespace ivec { +struct GraphLabel +{ + int64_t x; + int64_t y; + int layer_id; + int pin_id; +}; + +using Graph = boost::adjacency_list; +using Vertex = Graph::vertex_descriptor; +using Edge = Graph::edge_descriptor; + +struct EdgeHash +{ + size_t operator()(const Edge& e) const + { + size_t h1 = std::hash()(e.m_source); + size_t h2 = std::hash()(e.m_target); + return h1 ^ (h2 << 1); + } +}; +class GraphCheckerBase +{ + public: + GraphCheckerBase() {} + ~GraphCheckerBase() {} + + protected: + virtual bool isConnectivity(const Graph& graph) const; + virtual void writeToDot(const Graph& graph, const std::string& path) const; + virtual void writeToPy(VecNet& net, const std::string& path) const; + virtual void writeToPy(const Graph& graph, VecNet& net, const std::string& path, const bool& mark_break = false, + const bool& mark_pin_id = true) const; +}; + +class VecNetChecker : public GraphCheckerBase +{ + public: + VecNetChecker() {} + ~VecNetChecker() {} + + // check the connectivity of the net, wire, etc. + bool isLocalConnectivity(VecNet& net) const; + bool isLocalConnectivity(VecNetWire& wire) const; + + // convert the net to graph + Graph convertToGraph(VecNet& net) const; + + // write to py for debug + void writeToDot(const Graph& graph, const std::string& path) const; + void writeToPy(const Graph& graph, VecNet& net, const std::string& path, const bool& mark_break = false, + const bool& mark_pin_id = true) const; + + private: +}; + +class VecLayoutChecker : public GraphCheckerBase +{ + public: + VecLayoutChecker() {} + ~VecLayoutChecker() {} + + bool checkLayout(std::map net_map); + + void checkPinConnection(std::map net_map); + + private: +}; +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/graph/data_manager/vec_graph_dm.cpp b/src/vectorization/src/graph/data_manager/vec_graph_dm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be010fd1b32a02b52d94e21c2292e91142f225fd --- /dev/null +++ b/src/vectorization/src/graph/data_manager/vec_graph_dm.cpp @@ -0,0 +1,259 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** + +#include "vec_graph_dm.h" + +#include "Log.hh" +#include "idm.h" +#include "omp.h" +#include "usage.hh" +#include "vec_graph_check.hh" +#include "vec_grid_info.h" +#include "vec_net_graph_gen.hh" + +namespace ivec { + +#define debug_error 0 + +bool VecGraphDataManager::buildGraphData() +{ + auto get_nodes + = [&](int x1, int y1, int layer1, int x2, int y2, int layer2, VecLayoutLayers& layout_layers) -> std::pair { + if (layer1 == layer2) { + auto& grid = layout_layers.findLayoutLayer(layer1)->get_grid(); + + auto [row1, col1] = gridInfoInst.findNodeID(x1, y1); + auto* node1 = grid.get_node(row1, col1); + + auto [row2, col2] = gridInfoInst.findNodeID(x2, y2); + auto* node2 = grid.get_node(row2, col2); + + if (node1 == nullptr || node1->get_node_data() == nullptr || node2 == nullptr || node2->get_node_data() == nullptr) { + LOG_ERROR << "error node...."; + } + + node1->set_real_coordinate(x1, y1); + node2->set_real_coordinate(x2, y2); + + return std::make_pair(node1, node2); + } else { + auto& grid1 = layout_layers.findLayoutLayer(layer1)->get_grid(); + auto [row1, col1] = gridInfoInst.findNodeID(x1, y1); + auto* node1 = grid1.get_node(row1, col1); + + auto& grid2 = layout_layers.findLayoutLayer(layer2)->get_grid(); + auto [row2, col2] = gridInfoInst.findNodeID(x2, y2); + auto* node2 = grid2.get_node(row2, col2); + + if (node1 == nullptr || node1->get_node_data() == nullptr || node2 == nullptr || node2->get_node_data() == nullptr) { + LOG_ERROR << "error node...."; + } + + node1->set_real_coordinate(x1, y1); + node2->set_real_coordinate(x2, y2); + + return std::make_pair(node1, node2); + } + }; + + auto convert_to_routing_graph = [&](const WireGraph& wire_graph) -> NetRoutingGraph { + NetRoutingGraph routing_graph; + auto [v_iter, v_end] = boost::vertices(wire_graph); + for (; v_iter != v_end; ++v_iter) { + auto v = *v_iter; + auto x = wire_graph[v].x; + auto y = wire_graph[v].y; + auto layer_id = wire_graph[v].layer_id; + NetRoutingVertex vertex{ + .id = v, + .is_pin = wire_graph[v].is_pin, + .is_driver_pin = wire_graph[v].is_driver_pin, + .point = {x, y, layer_id}, + }; + routing_graph.vertices.emplace_back(vertex); + } + auto [e_iter, e_end] = boost::edges(wire_graph); + for (; e_iter != e_end; ++e_iter) { + auto e = *e_iter; + auto source = boost::source(e, wire_graph); + auto target = boost::target(e, wire_graph); + std::vector> wire_path = wire_graph[e].path; + // convert wire_path to path + if (wire_path.empty()) { + LOG_WARNING << "Empty path for edge: " << source << " -> " << target; + continue; + } + std::vector path; + std::ranges::for_each(wire_path, [&](const std::pair& point_pair) -> void { + path.emplace_back(NetRoutingPoint{bg::get<0>(point_pair.first), bg::get<1>(point_pair.first), bg::get<2>(point_pair.first)}); + }); + path.emplace_back( + NetRoutingPoint{bg::get<0>(wire_path.back().second), bg::get<1>(wire_path.back().second), bg::get<2>(wire_path.back().second)}); + NetRoutingEdge edge{ + .source_id = source, + .target_id = target, + .path = path, + }; + routing_graph.edges.emplace_back(edge); + } + return routing_graph; + }; + + ieda::Stats stats; + + auto* idb_design = dmInst->get_idb_design(); + auto idb_nets = idb_design->get_net_list()->get_net_list(); + VecNetGraphGenerator gen; + + auto& layout_graph = _layout->get_graph(); + auto& layout_layers = _layout->get_layout_layers(); + + omp_lock_t lck; + omp_init_lock(&lck); + + // auto* special_net_list = idb_design->get_special_net_list(); + // auto* vdd_net = special_net_list->find_net("VDD"); + // gen.buildTopoGraph(vdd_net); + + // #pragma omp parallel for schedule(dynamic) + for (size_t net_id = 0; net_id < idb_nets.size(); ++net_id) { + auto* idb_net = idb_nets[net_id]; + /// ignore net if pin number < 2 + if (idb_net->get_pin_number() < 2) { + continue; + } + if (gen.isCornerCase(idb_net)) { + continue; + } + auto wire_graph = gen.buildGraph(idb_net); + auto routing_graph = convert_to_routing_graph(wire_graph); + auto* vec_net = layout_graph.get_net(net_id); + vec_net->clearWire(); + vec_net->set_routing_graph(routing_graph); +#if debug_error + std::set pin_ids_wires; + std::set pin_ids_paths; +#endif + // travelsal the edge in wire_graph + for (auto edge : boost::make_iterator_range(boost::edges(wire_graph))) { + VecNetWire vec_wire; + /// add wire + { + auto source = boost::source(edge, wire_graph); + auto target = boost::target(edge, wire_graph); + + auto source_label = wire_graph[source]; + auto target_label = wire_graph[target]; + + auto [node1, node2] = get_nodes(source_label.x, source_label.y, source_label.layer_id, target_label.x, target_label.y, + target_label.layer_id, layout_layers); + + /// ignore same node + if (node1 == node2) { + continue; + } + + vec_wire.set_start(node1); + vec_wire.set_end(node2); +#if debug_error + if (node1->get_node_data()->get_pin_id() >= 0) { + pin_ids_wires.insert(node1->get_node_data()->get_pin_id()); + } + if (node2->get_node_data()->get_pin_id() >= 0) { + pin_ids_wires.insert(node2->get_node_data()->get_pin_id()); + } + + if ((node1->get_node_data()->get_pin_id() >= 0 && false == source_label.is_pin) + || (node1->get_node_data()->get_pin_id() == -1 && source_label.is_pin)) { + LOG_WARNING << "Warning, node1 pin mismatch. "; + } + + if ((node2->get_node_data()->get_pin_id() >= 0 && false == target_label.is_pin) + || (node2->get_node_data()->get_pin_id() == -1 && target_label.is_pin)) { + LOG_WARNING << "Warning, node2 pin mismatch. "; + } +#endif + } + + /// add path + +#if debug_error + VecNode* bk_start = nullptr; + VecNode* bk_end = nullptr; + int i = 0; +#endif + std::ranges::for_each(wire_graph[edge].path, [&](auto& point_pair) -> void { + auto start_point = point_pair.first; + auto end_point = point_pair.second; + auto [node1, node2] = get_nodes(bg::get<0>(start_point), bg::get<1>(start_point), bg::get<2>(start_point), bg::get<0>(end_point), + bg::get<1>(end_point), bg::get<2>(end_point), layout_layers); + + /// ignore same node + if (node1 != node2) { + vec_wire.add_path(node1, node2); + } +#if debug_error + if (i == 0) { + bk_end = node2; + } else { + bk_start = node1; + + if (bk_end != bk_start) { + std::ranges::for_each(wire_graph[edge].path, [&](auto& p) -> void { + LOG_INFO << "[" << bg::get<0>(p.first) << "," << bg::get<1>(p.first) << "," << bg::get<2>(p.first) << "] [" + << bg::get<0>(p.second) << "," << bg::get<1>(p.second) << "," << bg::get<2>(p.second) << "]"; + }); + } + + bk_end = node2; + } + + if (node1->get_node_data()->get_pin_id() >= 0) { + pin_ids_paths.insert(node1->get_node_data()->get_pin_id()); + } + if (node2->get_node_data()->get_pin_id() >= 0) { + pin_ids_paths.insert(node2->get_node_data()->get_pin_id()); + } +#endif + }); + + vec_net->addWire(vec_wire); + } + + if (net_id % 1000 == 0) { + LOG_INFO << "Read nets : " << net_id << " / " << (int) idb_nets.size(); + } +#if debug_error + if (pin_ids_wires.size() != vec_net->get_pin_ids().size()) { + LOG_WARNING << "Warning, pin size mismatch, name : " << _layout->findNetName(net_id) << " ,net id : " << net_id + << " ,net num : " << vec_net->get_pin_ids().size() << " ,wire num : " << pin_ids_wires.size() + << " ,path num: " << pin_ids_paths.size(); + } +#endif + } + + LOG_INFO << "Read nets : " << idb_nets.size() << " / " << (int) idb_nets.size(); + + omp_destroy_lock(&lck); + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization save json net end..."; + + return true; +} + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/graph/data_manager/vec_graph_dm.h b/src/vectorization/src/graph/data_manager/vec_graph_dm.h new file mode 100644 index 0000000000000000000000000000000000000000..5ab7793fe4d80aff9df84313cccc0ed30b8c3069 --- /dev/null +++ b/src/vectorization/src/graph/data_manager/vec_graph_dm.h @@ -0,0 +1,39 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "vec_layout.h" +#include "vec_net.h" + +namespace ivec { + +class VecGraphDataManager +{ + public: + VecGraphDataManager(VecLayout* layout) { _layout = layout; } + ~VecGraphDataManager() {} + + std::map& get_graph() { return _layout->get_graph().get_net_map(); } + + bool buildGraphData(); + + private: + VecLayout* _layout; +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/graph/data_manager/vec_graph_gui.cc b/src/vectorization/src/graph/data_manager/vec_graph_gui.cc new file mode 100644 index 0000000000000000000000000000000000000000..59dde16cd4caa6dd53e49a3ef832fab03e9131dd --- /dev/null +++ b/src/vectorization/src/graph/data_manager/vec_graph_gui.cc @@ -0,0 +1,799 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file vec_graph_gui.cc + * @author Dawn Li (dawnli619215645@gmail.com) + * @version 1.0 + * @date 2025-02-20 + * @brief the graph gui for vectorization + */ + +#include "vec_graph_gui.hh" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vec_net_graph_gen.hh" +namespace ivec { + +void VecShapeTableView::resizeEvent(QResizeEvent* event) +{ + QTableView::resizeEvent(event); + _setColumnWidths(); +} +void VecShapeTableView::_setColumnWidths() +{ + int total_width = viewport()->width(); + int class_column_width = total_width * 5.5 / 10; + int visible_column_width = total_width * 2.5 / 10; + int color_column_width = total_width * 2 / 10; + setColumnWidth(0, class_column_width); + setColumnWidth(1, visible_column_width); + setColumnWidth(2, color_column_width); +} +void VecColorItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + QString color_string = index.data(Qt::DisplayRole).toString(); + QColor color(color_string); + if (color.isValid()) { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing, true); + int side = qMin(option.rect.width(), option.rect.height()) - 8; + int left = option.rect.left() + (option.rect.width() - side) / 2; + int top = option.rect.top() + (option.rect.height() - side) / 2; + QRect square_rect(left, top, side, side); + painter->setBrush(color); + painter->setPen(Qt::NoPen); + painter->drawRoundedRect(square_rect, 4, 4); + QColor border_color = color.darker(150); + painter->setBrush(Qt::NoBrush); + painter->setPen(QPen(border_color, 1)); + painter->drawRoundedRect(square_rect, 4, 4); + painter->restore(); + } else { + QStyledItemDelegate::paint(painter, option, index); + } +} +bool VecColorItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, + const QModelIndex& index) +{ + if (event->type() == QEvent::MouseButtonPress) { + QMouseEvent* mouse_event = static_cast(event); + if ((mouse_event->button() == Qt::LeftButton) && (option.rect.contains(mouse_event->pos()))) { + QString color_string = index.data(Qt::DisplayRole).toString(); + QColor current_color(color_string); + if (!current_color.isValid()) { + current_color = QColor("#888"); + } + QPoint global_mouse_pos = mouse_event->globalPos(); + QRect screen_geometry = QApplication::desktop()->screenGeometry(global_mouse_pos); + QColorDialog dlg; + dlg.setCurrentColor(current_color); + dlg.setOption(QColorDialog::DontUseNativeDialog, true); + QPoint centered_pos = global_mouse_pos - QPoint(dlg.sizeHint().width() / 2, dlg.sizeHint().height() / 2); + if (!screen_geometry.contains(QRect(centered_pos, dlg.sizeHint()))) { + centered_pos = screen_geometry.center() - QPoint(dlg.sizeHint().width() / 2, dlg.sizeHint().height() / 2); + } + dlg.move(centered_pos); + if (dlg.exec() == QDialog::Accepted) { + QColor new_color = dlg.selectedColor(); + if (new_color.isValid()) { + model->setData(index, new_color.name(QColor::HexRgb), Qt::EditRole); + } + } + return true; + } + } + return QStyledItemDelegate::editorEvent(event, model, option, index); +} +VecGraphWidget::VecGraphWidget(QWidget* parent) + : QOpenGLWidget(parent), + _axes_visible(false), + _rotation_mode(false), + _zoom_factor(1.0f), + _pan_x(0.0f), + _pan_y(0.0f), + _rotation_x(45.0f), + _rotation_y(45.0f), + _rotation_z(45.0f), + _previous_filter_text("") +{ + setFocusPolicy(Qt::StrongFocus); + + _control_panel = new QWidget(this); + _control_panel->setObjectName("control_panel"); + _control_panel->setStyleSheet("background-color: #222; color: #eee;"); + + QVBoxLayout* panel_layout = new QVBoxLayout(_control_panel); + panel_layout->setContentsMargins(10, 10, 10, 10); + panel_layout->setSpacing(10); + + QHBoxLayout* button_layout = new QHBoxLayout(); + _rotation_button = new QToolButton(_control_panel); + _rotation_button->setText("Rotation Mode (Off)"); + _rotation_button->setCheckable(true); + + _reset_view_button = new QToolButton(_control_panel); + _reset_view_button->setText("Reset View"); + + button_layout->addWidget(_rotation_button); + button_layout->addWidget(_reset_view_button); + panel_layout->addLayout(button_layout); + + QString button_style = R"( + QToolButton { + background-color: #444; + color: #eee; + border: 1px solid #222; + border-radius: 4px; + padding: 4px; + } + QToolButton:checked { + background-color: #666; + } + QToolButton:hover { + background-color: #555; + } + )"; + _rotation_button->setStyleSheet(button_style); + _reset_view_button->setStyleSheet(button_style); + + _search_line_edit = new QLineEdit(_control_panel); + _search_line_edit->setPlaceholderText("Search filter..."); + _search_line_edit->setStyleSheet("padding: 4px; border: 1px solid #444; border-radius: 4px; background-color: #333; color: #eee;"); + + _hide_all_check_box = new QCheckBox("Hide All", _control_panel); + _show_all_check_box = new QCheckBox("Show All", _control_panel); + + QHBoxLayout* search_layout = new QHBoxLayout(); + search_layout->addWidget(_search_line_edit); + search_layout->addStretch(); + search_layout->addWidget(_hide_all_check_box); + search_layout->addWidget(_show_all_check_box); + + _unified_color_button = new QToolButton(_control_panel); + _unified_color_button->setStyleSheet( + "QToolButton {" + " border: 2px solid gray;" + " border-radius: 15px;" + " padding: 5px 10px;" + " color: white;" + " background: qlineargradient(" + " x1: 0, y1: 0, x2: 1, y2: 0," + " stop: 0 red, stop: 0.17 orange," + " stop: 0.33 yellow, stop: 0.5 green," + " stop: 0.67 cyan, stop: 0.83 blue," + " stop: 1 purple" + " );" + "}" + "QToolButton:hover {" + " background: qlineargradient(" + " x1: 0, y1: 0, x2: 1, y2: 0," + " stop: 0 purple, stop: 0.17 blue," + " stop: 0.33 cyan, stop: 0.5 green," + " stop: 0.67 yellow, stop: 0.83 orange," + " stop: 1 red" + " );" + "}" + "QToolButton:pressed {" + " background: qlineargradient(" + " x1: 0, y1: 0, x2: 1, y2: 0," + " stop: 0 black, stop: 1 white" + " );" + "}"); + _unified_color_button->setFixedSize(20, 20); + search_layout->addWidget(_unified_color_button); + + panel_layout->addLayout(search_layout); + + _filtering_group_box = new QGroupBox("Data Filtering", _control_panel); + _filtering_group_box->setStyleSheet( + "QGroupBox { background-color: #333; color: #eee; border: 1px solid #222; border-radius: 4px; margin-top: 10px; }" + "QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 5px 0 5px; }"); + + QVBoxLayout* filtering_box_layout = new QVBoxLayout(_filtering_group_box); + filtering_box_layout->setContentsMargins(5, 5, 5, 5); + + _class_model = new QStandardItemModel(this); + _class_model->setColumnCount(3); + _class_model->setHorizontalHeaderLabels({"Class", "Visible", "Color"}); + + _proxy_model = new QSortFilterProxyModel(this); + _proxy_model->setSourceModel(_class_model); + _proxy_model->setFilterCaseSensitivity(Qt::CaseInsensitive); + _proxy_model->setFilterKeyColumn(0); + + _table_view = new VecShapeTableView(_filtering_group_box); + _table_view->setModel(_proxy_model); + _table_view->setSelectionMode(QAbstractItemView::NoSelection); + _table_view->setSelectionBehavior(QAbstractItemView::SelectRows); + _table_view->horizontalHeader()->setStretchLastSection(true); + auto* color_delegate = new VecColorItemDelegate(_table_view); + _table_view->setItemDelegateForColumn(2, color_delegate); + + filtering_box_layout->addWidget(_table_view); + panel_layout->addWidget(_filtering_group_box); + panel_layout->addStretch(); + + connect(_hide_all_check_box, &QCheckBox::stateChanged, this, &VecGraphWidget::onHideAllChecked); + connect(_show_all_check_box, &QCheckBox::stateChanged, this, &VecGraphWidget::onShowAllChecked); + connect(_unified_color_button, &QToolButton::clicked, this, &VecGraphWidget::onUnifiedColorClicked); + + _search_timer = new QTimer(this); + _search_timer->setSingleShot(true); + _search_timer->setInterval(300); + connect(_search_timer, &QTimer::timeout, this, &VecGraphWidget::onSearchTimeout); + connect(_search_line_edit, &QLineEdit::textChanged, this, [this](const QString&) { _search_timer->start(); }); + + connect(_rotation_button, &QToolButton::clicked, this, &VecGraphWidget::toggleRotationMode); + connect(_reset_view_button, &QToolButton::clicked, this, &VecGraphWidget::resetView); + connect(_class_model, &QStandardItemModel::dataChanged, this, &VecGraphWidget::onClassModelDataChanged); + + _table_view->setColumnWidth(0, 100); + _table_view->setColumnWidth(1, 60); + _table_view->setColumnWidth(2, 60); + _table_view->setAttribute(Qt::WA_NoMousePropagation); +} + +void VecGraphWidget::addWire(float x1, float y1, float z, float x2, float y2, float, const std::string& comment, + const std::string& shape_class, const QVector3D& color) +{ + if (!((std::abs(x1 - x2) < 1e-6f) || (std::abs(y1 - y2) < 1e-6f))) { + return; + } + Shape shape; + shape.type = Wire; + shape.x1 = x1; + shape.y1 = y1; + shape.z1 = z; + shape.x2 = x2; + shape.y2 = y2; + shape.z2 = z; + shape.comment = comment; + shape.width = 5.0f; + shape.shape_class = shape_class; + QString class_name = QString::fromStdString(shape_class); + _shapes_by_class[class_name].push_back(shape); + _ensureClassInModel(class_name, color); + update(); +} + +void VecGraphWidget::addRect(float x1, float y1, float z, float x2, float y2, float, const std::string& comment, + const std::string& shape_class, const QVector3D& color) +{ + Shape shape; + shape.type = Rect; + shape.x1 = x1; + shape.y1 = y1; + shape.z1 = z; + shape.x2 = x2; + shape.y2 = y2; + shape.z2 = z; + shape.comment = comment; + shape.width = 0.0f; + shape.shape_class = shape_class; + QString class_name = QString::fromStdString(shape_class); + _shapes_by_class[class_name].push_back(shape); + _ensureClassInModel(class_name, color); + update(); +} + +void VecGraphWidget::addVia(float x, float y, float z1, float z2, const std::string& comment, const std::string& shape_class, + const QVector3D& color) +{ + Shape shape; + shape.type = Via; + shape.x1 = x; + shape.y1 = y; + shape.z1 = z1; + shape.x2 = x; + shape.y2 = y; + shape.z2 = z2; + shape.comment = comment; + shape.width = 5.0f; + shape.shape_class = shape_class; + QString class_name = QString::fromStdString(shape_class); + _shapes_by_class[class_name].push_back(shape); + _ensureClassInModel(class_name, color); + update(); +} + +void VecGraphWidget::autoScale() +{ + if (_shapes_by_class.isEmpty()) { + return; + } + float min_x = std::numeric_limits::max(); + float min_y = std::numeric_limits::max(); + float min_z = std::numeric_limits::max(); + float max_x = -std::numeric_limits::max(); + float max_y = -std::numeric_limits::max(); + float max_z = -std::numeric_limits::max(); + for (auto it = _shapes_by_class.begin(); it != _shapes_by_class.end(); ++it) { + const QVector& shape_list = it.value(); + for (const Shape& shape : shape_list) { + min_x = std::min(min_x, std::min(shape.x1, shape.x2)); + min_y = std::min(min_y, std::min(shape.y1, shape.y2)); + min_z = std::min(min_z, std::min(shape.z1, shape.z2)); + max_x = std::max(max_x, std::max(shape.x1, shape.x2)); + max_y = std::max(max_y, std::max(shape.y1, shape.y2)); + max_z = std::max(max_z, std::max(shape.z1, shape.z2)); + } + } + float dx = max_x - min_x; + float dy = max_y - min_y; + float dz = (max_z - min_z) * 10.0f; + if ((dx < 1e-6f) || (dy < 1e-6f) || (dz < 1e-6f)) { + return; + } + for (auto it = _shapes_by_class.begin(); it != _shapes_by_class.end(); ++it) { + QVector& shape_list = it.value(); + for (Shape& shape : shape_list) { + shape.x1 = ((shape.x1 - min_x) / dx) * 100.0f; + shape.x2 = ((shape.x2 - min_x) / dx) * 100.0f; + shape.y1 = ((shape.y1 - min_y) / dy) * 100.0f; + shape.y2 = ((shape.y2 - min_y) / dy) * 100.0f; + shape.z1 = ((shape.z1 - min_z) / dz) * 100.0f; + shape.z2 = ((shape.z2 - min_z) / dz) * 100.0f; + } + } + initView(); +} + +void VecGraphWidget::showAxes() +{ + _axes_visible = true; + update(); +} + +void VecGraphWidget::initView() +{ + if (_shapes_by_class.isEmpty()) { + _zoom_factor = 1.0f; + _pan_x = 0.0f; + _pan_y = 0.0f; + _rotation_x = -45.0f; + _rotation_y = 0.0f; + _rotation_z = -45.0f; + update(); + return; + } + float min_x = std::numeric_limits::max(); + float min_y = std::numeric_limits::max(); + float min_z = std::numeric_limits::max(); + float max_x = -std::numeric_limits::max(); + float max_y = -std::numeric_limits::max(); + float max_z = -std::numeric_limits::max(); + for (auto it = _shapes_by_class.begin(); it != _shapes_by_class.end(); ++it) { + const QVector& shape_list = it.value(); + for (const Shape& shape : shape_list) { + min_x = std::min(min_x, std::min(shape.x1, shape.x2)); + min_y = std::min(min_y, std::min(shape.y1, shape.y2)); + min_z = std::min(min_z, std::min(shape.z1, shape.z2)); + max_x = std::max(max_x, std::max(shape.x1, shape.x2)); + max_y = std::max(max_y, std::max(shape.y1, shape.y2)); + max_z = std::max(max_z, std::max(shape.z1, shape.z2)); + } + } + float center_x = 0.5f * (min_x + max_x); + float center_y = 0.5f * (min_y + max_y); + _pan_x = -center_x; + _pan_y = -center_y; + float dx = max_x - min_x; + float dy = max_y - min_y; + float dz = (max_z - min_z) * 10.0f; + float radius = std::sqrt(dx * dx + dy * dy + dz * dz) * 0.5f; + float fov_rad = 45.0f * 3.14159265f / 180.0f; + float d = radius / std::tan(fov_rad / 2.0f); + _zoom_factor = d / 50.0f; + _rotation_x = -45.0f; + _rotation_y = 0.0f; + _rotation_z = -45.0f; + update(); +} + +void VecGraphWidget::initializeGL() +{ + initializeOpenGLFunctions(); + glClearColor(0.15f, 0.15f, 0.15f, 1.0f); + glEnable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); +} + +void VecGraphWidget::resizeGL(int w, int h) +{ + glViewport(0, 0, w, h); + _projection.setToIdentity(); + _projection.perspective(45.0f, GLfloat(w) / h, 0.1f, 1000.0f); +} + +void VecGraphWidget::paintGL() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + QMatrix4x4 model_view; + model_view.translate(_pan_x, _pan_y, -75.0f * _zoom_factor); + model_view.rotate(_rotation_x, 1, 0, 0); + model_view.rotate(_rotation_y, 0, 1, 0); + model_view.rotate(_rotation_z, 0, 0, 1); + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(_projection.constData()); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(model_view.constData()); + for (auto it = _shapes_by_class.begin(); it != _shapes_by_class.end(); ++it) { + QString class_name = it.key(); + if ((!_class_visibility.contains(class_name)) || (!_class_visibility[class_name])) { + continue; + } + QVector3D draw_color = _class_colors.value(class_name, QVector3D(1, 1, 1)); + glColor3f(draw_color.x(), draw_color.y(), draw_color.z()); + glLineWidth(5.0f); + const QVector& shape_list = it.value(); + for (const Shape& shape : shape_list) { + switch (shape.type) { + case Wire: { + glBegin(GL_LINES); + glVertex3f(shape.x1, shape.y1, shape.z1); + glVertex3f(shape.x2, shape.y2, shape.z2); + glEnd(); + break; + } + case Rect: { + glBegin(GL_QUADS); + glVertex3f(shape.x1, shape.y1, shape.z1); + glVertex3f(shape.x2, shape.y1, shape.z1); + glVertex3f(shape.x2, shape.y2, shape.z2); + glVertex3f(shape.x1, shape.y2, shape.z2); + glEnd(); + break; + } + case Via: { + glBegin(GL_LINES); + glVertex3f(shape.x1, shape.y1, shape.z1); + glVertex3f(shape.x2, shape.y2, shape.z2); + glEnd(); + break; + } + } + } + } + if (_axes_visible) { + _drawAxes(); + } +} + +void VecGraphWidget::mousePressEvent(QMouseEvent* event) +{ + if (event->pos().x() < _control_panel->width()) { + return; + } + _last_mouse_pos = event->pos(); +} + +void VecGraphWidget::mouseMoveEvent(QMouseEvent* event) +{ + if (event->pos().x() < _control_panel->width()) { + return; + } + int dx = event->x() - _last_mouse_pos.x(); + int dy = event->y() - _last_mouse_pos.y(); + if (_rotation_mode) { + if (event->modifiers() & Qt::ShiftModifier) { + _rotation_z += dx; + } else { + _rotation_x += dy; + _rotation_y += dx; + } + } else { + _pan_x += dx * 0.05f; + _pan_y -= dy * 0.05f; + } + _last_mouse_pos = event->pos(); + update(); +} + +void VecGraphWidget::wheelEvent(QWheelEvent* event) +{ +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + QPoint angle_delta = event->angleDelta(); +#else + QPoint angle_delta = event->angleDelta(); +#endif + if (event->pos().x() < _control_panel->width()) { + return; + } + if (angle_delta.y() > 0) { + _zoom_factor *= 0.9f; + } else { + _zoom_factor *= 1.1f; + } + update(); +} + +bool VecGraphWidget::event(QEvent* e) +{ + if (e->type() == QEvent::ToolTip) { + QHelpEvent* help_event = static_cast(e); + if (help_event->pos().x() < _control_panel->width()) { + QToolTip::hideText(); + e->ignore(); + return true; + } + QMatrix4x4 model_view; + model_view.translate(_pan_x, _pan_y, -75.0f * _zoom_factor); + model_view.rotate(_rotation_x, 1, 0, 0); + model_view.rotate(_rotation_y, 0, 1, 0); + model_view.rotate(_rotation_z, 0, 0, 1); + const int threshold = 10; + for (auto it = _shapes_by_class.begin(); it != _shapes_by_class.end(); ++it) { + const QString& class_name = it.key(); + if (!_class_visibility.value(class_name, true)) { + continue; + } + const QVector& shape_list = it.value(); + for (const Shape& shape : shape_list) { + float mid_x = 0.5f * (shape.x1 + shape.x2); + float mid_y = 0.5f * (shape.y1 + shape.y2); + float mid_z = 0.5f * (shape.z1 + shape.z2); + QVector3D world_pos(mid_x, mid_y, mid_z); + QVector3D screen_pos = _project(world_pos, model_view, _projection); + QPointF shape_point(screen_pos.x(), screen_pos.y()); + if ((help_event->pos() - shape_point).manhattanLength() < threshold) { + QToolTip::showText(help_event->globalPos(), QString::fromStdString(shape.comment), this); + return true; + } + } + } + QToolTip::hideText(); + e->ignore(); + return true; + } + return QOpenGLWidget::event(e); +} + +void VecGraphWidget::resizeEvent(QResizeEvent* event) +{ + QOpenGLWidget::resizeEvent(event); + int new_width = event->size().width(); + int new_height = event->size().height(); + _control_panel->setGeometry(0, 0, int(new_width * 0.2), new_height); +} + +void VecGraphWidget::toggleRotationMode(bool checked) +{ + _rotation_mode = checked; + _rotation_button->setText(checked ? "Rotation Mode (On)" : "Rotation Mode (Off)"); +} + +void VecGraphWidget::resetView() +{ + initView(); +} + +void VecGraphWidget::onHideAllChecked(int state) +{ + if (state == Qt::Checked) { + _show_all_check_box->setChecked(false); + int row_count_proxy = _proxy_model->rowCount(); + for (int i = 0; i < row_count_proxy; ++i) { + QModelIndex proxy_index = _proxy_model->index(i, 1); + if (!proxy_index.isValid()) { + continue; + } + QModelIndex source_index = _proxy_model->mapToSource(proxy_index); + if (!source_index.isValid()) { + continue; + } + QStandardItem* item = _class_model->itemFromIndex(source_index); + if (!item) { + continue; + } + QStandardItem* visible_item = _class_model->item(source_index.row(), 1); + if (visible_item) { + visible_item->setCheckState(Qt::Unchecked); + } + } + update(); + } +} + +void VecGraphWidget::onShowAllChecked(int state) +{ + if (state == Qt::Checked) { + _hide_all_check_box->setChecked(false); + int row_count_proxy = _proxy_model->rowCount(); + for (int i = 0; i < row_count_proxy; ++i) { + QModelIndex proxy_index = _proxy_model->index(i, 1); + if (!proxy_index.isValid()) { + continue; + } + QModelIndex source_index = _proxy_model->mapToSource(proxy_index); + if (!source_index.isValid()) { + continue; + } + QStandardItem* visible_item = _class_model->item(source_index.row(), 1); + if (visible_item) { + visible_item->setCheckState(Qt::Checked); + } + } + update(); + } +} + +void VecGraphWidget::onUnifiedColorClicked() +{ + QColor current_color("#888"); + QColorDialog dialog(current_color, this); + dialog.setWindowTitle("Select Unified Color"); + dialog.setOptions(QColorDialog::DontUseNativeDialog); + QPoint global_mouse_pos = QCursor::pos(); + QRect screen_geometry = QApplication::desktop()->screenGeometry(global_mouse_pos); + QPoint centered_pos = global_mouse_pos - QPoint(dialog.sizeHint().width() / 2, dialog.sizeHint().height() / 2); + if (!screen_geometry.contains(QRect(centered_pos, dialog.sizeHint()))) { + centered_pos = screen_geometry.center() - QPoint(dialog.sizeHint().width() / 2, dialog.sizeHint().height() / 2); + } + dialog.move(centered_pos); + if (dialog.exec() != QDialog::Accepted) { + return; + } + QColor new_color = dialog.selectedColor(); + if (!new_color.isValid()) { + return; + } + int row_count_proxy = _proxy_model->rowCount(); + for (int i = 0; i < row_count_proxy; ++i) { + QModelIndex proxy_index_visible = _proxy_model->index(i, 1); + QModelIndex proxy_index_color = _proxy_model->index(i, 2); + if ((!proxy_index_visible.isValid()) || (!proxy_index_color.isValid())) { + continue; + } + QModelIndex source_index_visible = _proxy_model->mapToSource(proxy_index_visible); + QModelIndex source_index_color = _proxy_model->mapToSource(proxy_index_color); + if ((!source_index_visible.isValid()) || (!source_index_color.isValid())) { + continue; + } + QStandardItem* visible_item = _class_model->item(source_index_visible.row(), 1); + if (!visible_item) { + continue; + } + if (visible_item->checkState() == Qt::Checked) { + _class_model->setData(source_index_color, new_color.name(QColor::HexRgb), Qt::EditRole); + } + } + update(); +} + +void VecGraphWidget::onSearchTimeout() +{ + QString text = _search_line_edit->text(); + if (text == _previous_filter_text) { + return; + } + _previous_filter_text = text; + _proxy_model->setFilterRegExp(text); +} + +void VecGraphWidget::onClassModelDataChanged(const QModelIndex& top_left, const QModelIndex& bottom_right, const QVector& roles) +{ + Q_UNUSED(bottom_right); + Q_UNUSED(roles); + if (!top_left.isValid()) { + return; + } + int row = top_left.row(); + int col = top_left.column(); + QStandardItem* class_item = _class_model->item(row, 0); + QStandardItem* visible_item = _class_model->item(row, 1); + QStandardItem* color_item = _class_model->item(row, 2); + if ((!class_item) || (!visible_item) || (!color_item)) { + return; + } + QString class_name = class_item->text(); + if (col == 1) { + bool visible = (visible_item->checkState() == Qt::Checked); + _class_visibility[class_name] = visible; + } else if (col == 2) { + QString color_string = color_item->text(); + QColor c(color_string); + if (c.isValid()) { + _class_colors[class_name] = QVector3D(c.redF(), c.greenF(), c.blueF()); + } + } + update(); +} +void VecGraphWidget::_ensureClassInModel(const QString& class_name, const QVector3D& default_color) +{ + if (_class_indices.contains(class_name)) { + return; + } + if (!_class_colors.contains(class_name)) { + _class_colors[class_name] = default_color; + } + if (!_class_visibility.contains(class_name)) { + _class_visibility[class_name] = true; + } + QList row_items; + QStandardItem* name_item = new QStandardItem(class_name); + name_item->setFlags(name_item->flags() & ~Qt::ItemIsEditable); + QStandardItem* visible_item = new QStandardItem(); + visible_item->setCheckable(true); + visible_item->setCheckState(Qt::Checked); + QColor c = QColor::fromRgbF(default_color.x(), default_color.y(), default_color.z()); + QStandardItem* color_item = new QStandardItem(c.name(QColor::HexRgb)); + row_items << name_item << visible_item << color_item; + int new_row = _class_model->rowCount(); + _class_model->appendRow(row_items); + _class_indices[class_name] = new_row; +} + +void VecGraphWidget::_drawAxes() +{ + glLineWidth(3.0f); + glColor3f(0.31f, 0.70f, 0.45f); + glBegin(GL_LINES); + glVertex3f(0, 0, 0); + glVertex3f(105, 0, 0); + glEnd(); + glColor3f(0.85f, 0.58f, 0.56f); + glBegin(GL_LINES); + glVertex3f(0, 0, 0); + glVertex3f(0, 105, 0); + glEnd(); + glColor3f(0.19f, 0.52f, 0.61f); + glBegin(GL_LINES); + glVertex3f(0, 0, 0); + glVertex3f(0, 0, 105); + glEnd(); + for (int i = 0; i <= 10; ++i) { + float tick = i * 10.0f; + glColor3f(0.31f, 0.70f, 0.45f); + glBegin(GL_LINES); + glVertex3f(tick, -1.0f, 0); + glVertex3f(tick, 1.0f, 0); + glEnd(); + glColor3f(0.85f, 0.58f, 0.56f); + glBegin(GL_LINES); + glVertex3f(-1.0f, tick, 0); + glVertex3f(1.0f, tick, 0); + glEnd(); + glColor3f(0.19f, 0.52f, 0.61f); + glBegin(GL_LINES); + glVertex3f(0, 0, tick); + glVertex3f(0, 1.0f, tick); + glEnd(); + } +} + +QVector3D VecGraphWidget::_project(const QVector3D& obj, const QMatrix4x4& model_view, const QMatrix4x4& proj) +{ + QVector4D tmp(obj, 1.0f); + QVector4D eye = model_view * tmp; + QVector4D clip = proj * eye; + if (std::abs(clip.w()) < 1e-6f) { + return QVector3D(); + } + QVector3D ndc(clip.x() / clip.w(), clip.y() / clip.w(), clip.z() / clip.w()); + float x = (ndc.x() + 1.0f) * width() / 2.0f; + float y = (1.0f - ndc.y()) * height() / 2.0f; + return QVector3D(x, y, ndc.z()); +} +} // namespace ivec diff --git a/src/vectorization/src/graph/data_manager/vec_graph_gui.hh b/src/vectorization/src/graph/data_manager/vec_graph_gui.hh new file mode 100644 index 0000000000000000000000000000000000000000..0ec39489b8d0446adde074d9a27b8f0720b847fa --- /dev/null +++ b/src/vectorization/src/graph/data_manager/vec_graph_gui.hh @@ -0,0 +1,173 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file vec_graph_gui.hh + * @author Dawn Li (dawnli619215645@gmail.com) + * @version 1.0 + * @date 2025-02-20 + * @brief the graph gui for vectorization + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ivec { + +class VecShapeTableView : public QTableView +{ + Q_OBJECT + + public: + VecShapeTableView(QWidget* parent = nullptr) : QTableView(parent) + { + horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); + _setColumnWidths(); + } + + protected: + void resizeEvent(QResizeEvent* event) override; + + private: + void _setColumnWidths(); +}; + +class VecColorItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT + public: + using QStyledItemDelegate::QStyledItemDelegate; + + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; + + bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) override; +}; + +class VecGraphWidget : public QOpenGLWidget, protected QOpenGLFunctions +{ + Q_OBJECT + public: + enum ShapeType + { + Wire, + Rect, + Via + }; + + struct Shape + { + ShapeType type; + float x1, y1, z1; + float x2, y2, z2; + std::string comment; + float width; + std::string shape_class; + }; + + public: + explicit VecGraphWidget(QWidget* parent = nullptr); + ~VecGraphWidget() override {} + + void addWire(float x1, float y1, float z, float x2, float y2, float /*z2*/, const std::string& comment, + const std::string& shape_class = "Component 1", const QVector3D& color = QVector3D(0.92f, 0.62f, 0.15f)); + void addRect(float x1, float y1, float z, float x2, float y2, float /*z2*/, const std::string& comment, + const std::string& shape_class = "Component 1", const QVector3D& color = QVector3D(0.7f, 0.04f, 0.0f)); + void addVia(float x, float y, float z1, float z2, const std::string& comment, const std::string& shape_class = "Component 1", + const QVector3D& color = QVector3D(0.75f, 0.75f, 0.75f)); + + void autoScale(); + void showAxes(); + void initView(); + + protected: + void initializeGL() override; + void resizeGL(int w, int h) override; + void paintGL() override; + void mousePressEvent(QMouseEvent* event) override; + void mouseMoveEvent(QMouseEvent* event) override; + void wheelEvent(QWheelEvent* event) override; + bool event(QEvent* e) override; + void resizeEvent(QResizeEvent* event) override; + + private slots: + void toggleRotationMode(bool checked); + void resetView(); + void onHideAllChecked(int state); + void onShowAllChecked(int state); + void onUnifiedColorClicked(); + void onSearchTimeout(); + void onClassModelDataChanged(const QModelIndex& top_left, const QModelIndex& bottom_right, const QVector& roles); + + private: + void _ensureClassInModel(const QString& class_name, const QVector3D& default_color); + void _drawAxes(); + QVector3D _project(const QVector3D& obj, const QMatrix4x4& model_view, const QMatrix4x4& proj); + + private: + bool _axes_visible; + bool _rotation_mode; + QPoint _last_mouse_pos; + float _zoom_factor; + float _pan_x, _pan_y; + float _rotation_x, _rotation_y, _rotation_z; + QMatrix4x4 _projection; + QWidget* _control_panel; + QToolButton* _rotation_button; + QToolButton* _reset_view_button; + QGroupBox* _filtering_group_box; + QLineEdit* _search_line_edit; + QToolButton* _unified_color_button; + QCheckBox* _hide_all_check_box; + QCheckBox* _show_all_check_box; + QStandardItemModel* _class_model; + QSortFilterProxyModel* _proxy_model; + VecShapeTableView* _table_view; + QHash _class_indices; + QHash> _shapes_by_class; + QHash _class_colors; + QHash _class_visibility; + QTimer* _search_timer; + QString _previous_filter_text; +}; + +} // namespace ivec diff --git a/src/vectorization/src/graph/data_manager/vec_net_graph_gen.cc b/src/vectorization/src/graph/data_manager/vec_net_graph_gen.cc new file mode 100644 index 0000000000000000000000000000000000000000..33a48ef9175bf4ca013338412d3444a0b1d7f202 --- /dev/null +++ b/src/vectorization/src/graph/data_manager/vec_net_graph_gen.cc @@ -0,0 +1,1871 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file vec_net_graph_gen.cc + * @author Dawn Li (dawnli619215645@gmail.com) + * @version 1.0 + * @date 2024-11-29 + * @brief Construct graph from net data. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "IdbPins.h" +#include "idm.h" +#include "log/Log.hh" +#include "vec_net_graph_gen.hh" +#ifdef BUILD_VEC_GUI +#include "vec_graph_gui.hh" +#endif + +namespace ivec { +void VecNetGraphGenerator::initLayerMap() +{ + auto* idb_layout = dmInst->get_idb_layout(); + auto* idb_layers = idb_layout->get_layers(); + auto idb_layer_1st = dmInst->get_config().get_routing_layer_1st(); + auto layers = idb_layers->get_layers(); + + // Define the range starting from the 'idb_layer_1st' + // and ending before the first non-routing, non-cut layer + auto layer_range = layers | std::views::drop_while([&](auto* layer) -> bool { return layer->get_name() != idb_layer_1st; }) + | std::views::take_while([&](auto* layer) -> bool { return layer->is_routing() || layer->is_cut(); }); + + int index = 0; + std::ranges::for_each(layer_range, [&](auto* layer) -> void { _layer_map[layer->get_name()] = index++; }); + + LOG_INFO << "Layer number : " << index; +} +WireGraph VecNetGraphGenerator::buildGraph(idb::IdbNet* idb_net) const +{ + if (isCornerCase(idb_net)) { + return buildCornerCaseGraph(idb_net); + } + auto topo_graph = buildTopoGraph(idb_net); + auto wire_graph = buildWireGraph(topo_graph); + return wire_graph; +} +std::vector VecNetGraphGenerator::buildGraphs() const +{ + auto* idb_design = dmInst->get_idb_design(); + auto* idb_nets = idb_design->get_net_list(); + std::vector graphs; + std::ranges::transform(idb_nets->get_net_list(), std::back_inserter(graphs), + [&](auto* idb_net) -> WireGraph { return buildGraph(idb_net); }); + return graphs; +} +bool VecNetGraphGenerator::isCornerCase(idb::IdbNet* idb_net) const +{ + auto* driver_pin = idb_net->get_driving_pin(); + if (!driver_pin) { + return true; + } + auto io_pins = idb_net->get_io_pins()->get_pin_list(); + if (io_pins.size() != 1) { + return false; + } + + auto* io_pin = io_pins.front(); + auto io_shapes = io_pin->get_port_box_list(); + if (io_shapes.empty()) { + return true; + } + + return false; +} +WireGraph VecNetGraphGenerator::buildCornerCaseGraph(idb::IdbNet* idb_net) const +{ + // corner case: only one IO pin and one PAD + WireGraph wire_graph; + auto* pad = idb_net->get_instance_pin_list()->get_pin_list().front(); + + auto* pin_shape = pad->get_port_box_list().front(); + auto rect = pin_shape->get_rect_list().front(); + auto low_x = rect->get_low_x(); + auto low_y = rect->get_low_y(); + auto high_x = rect->get_high_x(); + auto high_y = rect->get_high_y(); + auto layer_id = _layer_map.at(pin_shape->get_layer()->get_name()); + auto io_location = LayoutDefPoint(low_x, low_y, layer_id); + + auto pad_vertex = boost::add_vertex(wire_graph); + wire_graph[pad_vertex].x = (low_x + high_x) / 2; + wire_graph[pad_vertex].y = (low_y + high_y) / 2; + wire_graph[pad_vertex].layer_id = layer_id; + wire_graph[pad_vertex].is_pin = true; + + auto io_vertex = boost::add_vertex(wire_graph); + wire_graph[io_vertex].x = (low_x + high_x) / 2; + wire_graph[io_vertex].y = (low_y + high_y) / 2; + wire_graph[io_vertex].layer_id = layer_id; + wire_graph[io_vertex].is_pin = true; + + auto edge = boost::add_edge(pad_vertex, io_vertex, wire_graph).first; + wire_graph[edge].path.emplace_back(std::make_pair(io_location, io_location)); + + return wire_graph; +} +TopoGraph VecNetGraphGenerator::buildTopoGraph(idb::IdbNet* idb_net) const +{ + // LOG_INFO << "Net name : " << idb_net->get_net_name(); + + TopoGraph graph; + // Build Instances' pins and IO pins + auto* driver_pin = idb_net->get_driving_pin(); + std::vector pins; + std::ranges::copy(idb_net->get_instance_pin_list()->get_pin_list(), std::back_inserter(pins)); + std::ranges::copy(idb_net->get_io_pins()->get_pin_list(), std::back_inserter(pins)); + std::ranges::for_each(pins, [&](auto* idb_pin) -> void { + auto vertex = boost::add_vertex(graph); + auto* layout_pin = new LayoutPin(idb_net->get_net_name(), idb_pin->get_pin_name(), idb_pin == driver_pin); + graph[vertex].content = layout_pin; + for (auto* layer_shape : idb_pin->get_port_box_list()) { + auto layer_name = layer_shape->get_layer()->get_name(); + auto layer_id = _layer_map.at(layer_name); + if (layer_shape->is_via()) { + std::ranges::for_each(layer_shape->get_rect_list(), [&](auto* rect) -> void { layout_pin->addViaCut(rect, layer_id); }); + } else { + std::ranges::for_each(layer_shape->get_rect_list(), [&](auto* rect) -> void { layout_pin->addPinShape(rect, layer_id); }); + } + } + }); + + // Build Wires + auto* idb_wires = idb_net->get_wire_list(); + for (auto* idb_wire : idb_wires->get_wire_list()) { + for (auto* idb_segment : idb_wire->get_segment_list()) { + if (idb_segment->is_rect()) { + auto* coord_start = idb_segment->get_point_start(); + auto* delta_rect = idb_segment->get_delta_rect(); + auto* rect = new idb::IdbRect(delta_rect); + rect->moveByStep(coord_start->get_x(), coord_start->get_y()); + auto layer_id = _layer_map.at(idb_segment->get_layer()->get_name()); + auto* patch = new LayoutPatch(rect, layer_id); + delete rect; + auto vertex = boost::add_vertex(graph); + graph[vertex].content = patch; + } + if (idb_segment->is_via()) { + std::ranges::for_each(idb_segment->get_via_list(), [&](auto* idb_via) -> void { + auto* coord = idb_via->get_coordinate(); + auto enclosure_bottom = idb_via->get_bottom_layer_shape(); + auto enclosure_top = idb_via->get_top_layer_shape(); + auto layer_shape = idb_via->get_cut_layer_shape(); + auto layer_name = layer_shape.get_layer()->get_name(); + auto cur_layer_id = _layer_map.at(layer_name); + std::vector bottom_shapes; + std::vector top_shapes; + auto* via = new LayoutVia(coord, enclosure_bottom.get_rect_list(), enclosure_top.get_rect_list(), cur_layer_id); + auto vertex = boost::add_vertex(graph); + graph[vertex].content = via; + }); + } + if (idb_segment->is_wire()) { + auto* coord_start = idb_segment->get_point_start(); + auto* coord_end = idb_segment->get_point_second(); + auto layer_id = _layer_map.at(idb_segment->get_layer()->get_name()); + auto* wire = new LayoutWire(coord_start, coord_end, layer_id); + auto vertex = boost::add_vertex(graph); + graph[vertex].content = wire; + } + } + } + buildConnections(graph); + checkConnectivity(graph); + return graph; +} + +TopoGraph VecNetGraphGenerator::buildTopoGraph(idb::IdbSpecialNet* idb_net) const +{ + // LOG_INFO << "Net name : " << idb_net->get_net_name(); + + TopoGraph graph; + // Build Instances' pins and IO pins + std::vector pins; + std::ranges::copy(idb_net->get_instance_pin_list()->get_pin_list(), std::back_inserter(pins)); + std::ranges::copy(idb_net->get_io_pin_list()->get_pin_list(), std::back_inserter(pins)); + // Corner Case: ignore the bottom layer + auto is_bottom_pin = [&](auto* idb_pin) -> bool { + for (auto* layer_shape : idb_pin->get_port_box_list()) { + auto layer_name = layer_shape->get_layer()->get_name(); + if (_layer_map.at(layer_name) == 0) { + return true; + } + } + return false; + }; + std::ranges::for_each(pins, [&](auto* idb_pin) -> void { + if (is_bottom_pin(idb_pin)) { + return; + } + auto vertex = boost::add_vertex(graph); + auto* layout_pin = new LayoutPin(); + graph[vertex].content = layout_pin; + for (auto* layer_shape : idb_pin->get_port_box_list()) { + auto layer_name = layer_shape->get_layer()->get_name(); + auto layer_id = _layer_map.at(layer_name); + if (layer_shape->is_via()) { + std::ranges::for_each(layer_shape->get_rect_list(), [&](auto* rect) -> void { layout_pin->addViaCut(rect, layer_id); }); + } else { + std::ranges::for_each(layer_shape->get_rect_list(), [&](auto* rect) -> void { layout_pin->addPinShape(rect, layer_id); }); + } + } + }); + + // Build Wires + // Corner Case: ignore the bottom layer + auto is_bottom_segment = [&](auto* idb_segment) -> bool { + auto layer_name = idb_segment->get_layer()->get_name(); + return _layer_map.at(layer_name) == 0; + }; + auto* idb_wires = idb_net->get_wire_list(); + for (auto* idb_wire : idb_wires->get_wire_list()) { + for (auto* idb_segment : idb_wire->get_segment_list()) { + if (is_bottom_segment(idb_segment)) { + continue; + } + + if (idb_segment->is_rect()) { + auto* coord_start = idb_segment->get_point_start(); + auto* delta_rect = idb_segment->get_delta_rect(); + auto* rect = new idb::IdbRect(delta_rect); + rect->moveByStep(coord_start->get_x(), coord_start->get_y()); + auto layer_id = _layer_map.at(idb_segment->get_layer()->get_name()); + auto* patch = new LayoutPatch(rect, layer_id); + delete rect; + auto vertex = boost::add_vertex(graph); + graph[vertex].content = patch; + } + if (idb_segment->is_via()) { + auto* idb_via = idb_segment->get_via(); + auto* coord = idb_via->get_coordinate(); + auto enclosure_bottom = idb_via->get_bottom_layer_shape(); + auto enclosure_top = idb_via->get_top_layer_shape(); + auto layer_shape = idb_via->get_cut_layer_shape(); + auto layer_name = layer_shape.get_layer()->get_name(); + auto cur_layer_id = _layer_map.at(layer_name); + std::vector bottom_shapes; + std::vector top_shapes; + auto* via = new LayoutVia(coord, enclosure_bottom.get_rect_list(), enclosure_top.get_rect_list(), cur_layer_id); + auto vertex = boost::add_vertex(graph); + graph[vertex].content = via; + } + if (idb_segment->is_line()) { + auto* coord_start = idb_segment->get_point_start(); + auto* coord_end = idb_segment->get_point_second(); + auto layer_id = _layer_map.at(idb_segment->get_layer()->get_name()); + auto* wire = new LayoutWire(coord_start, coord_end, layer_id); + auto vertex = boost::add_vertex(graph); + graph[vertex].content = wire; + } + } + } + buildConnections(graph); + checkConnectivity(graph); + return graph; +} +LayoutShapeManager VecNetGraphGenerator::buildShapeManager(const TopoGraph& graph) const +{ + LayoutShapeManager shape_manager; + + auto [v_iter, v_end] = boost::vertices(graph); + for (; v_iter != v_end; ++v_iter) { + auto v = *v_iter; + auto* content = graph[v].content; + if (content->is_patch()) { + auto* patch = static_cast(content); + shape_manager.addShape(patch->rect, v); + } else if (content->is_wire()) { + auto* wire = static_cast(content); + auto z = getZ(wire->start); + auto [x1, x2] = std::ranges::minmax({getX(wire->start), getX(wire->end)}); + auto [y1, y2] = std::ranges::minmax({getY(wire->start), getY(wire->end)}); + shape_manager.addShape(LayoutDefRect({x1, y1, z}, {x2, y2, z}), v); + } else if (content->is_via()) { + auto* via = static_cast(content); + shape_manager.addShape(via->cut_path, v); + for (auto& bottom_shape : via->bottom_shapes) { + shape_manager.addShape(bottom_shape, v); + } + for (auto& top_shape : via->top_shapes) { + shape_manager.addShape(top_shape, v); + } + } else if (content->is_pin()) { + auto* pin = static_cast(content); + for (auto& pin_shape : pin->pin_shapes) { + shape_manager.addShape(pin_shape, v); + } + for (auto& via_cut : pin->via_cuts) { + shape_manager.addShape(via_cut, v); + } + } else { + LOG_FATAL << "Unknown content type"; + } + } + + return shape_manager; +} +void VecNetGraphGenerator::buildConnections(TopoGraph& graph) const +{ + auto shape_manager = buildShapeManager(graph); + + // Find intersections + auto connect = [&](const size_t& ref, const std::vector& intersections) -> void { + LOG_FATAL_IF(intersections.empty()) << "No intersections found"; + for (const auto& id : intersections) { + if (id != ref && !boost::edge(ref, id, graph).second) { + // except itself and no duplicate edge + boost::add_edge(ref, id, graph); + } + } + }; + + auto [v_iter, v_end] = boost::vertices(graph); + for (; v_iter != v_end; ++v_iter) { + auto v = *v_iter; + auto* content = graph[v].content; + if (content->is_patch()) { + auto* patch = static_cast(content); + // for patch, find the intersections of the rect + auto intersections = shape_manager.findIntersections(patch->rect); + connect(v, intersections); + } else if (content->is_wire()) { + auto* wire = static_cast(content); + // for wire, find the intersections of the wire + auto intersections = shape_manager.findIntersections(wire->start, wire->end); + connect(v, intersections); + } else if (content->is_via()) { + auto* via = static_cast(content); + // for via, find the intersections of the cut path, bottom shapes and top shapes + auto cut_intersections = shape_manager.findIntersections(via->cut_path); + connect(v, cut_intersections); + for (auto& bottom_shape : via->bottom_shapes) { + auto intersections = shape_manager.findIntersections(bottom_shape); + connect(v, intersections); + } + for (auto& top_shape : via->top_shapes) { + auto intersections = shape_manager.findIntersections(top_shape); + connect(v, intersections); + } + } else if (content->is_pin()) { + auto* pin = static_cast(content); + // for pin, find the intersections of the pin shapes and via cuts + for (auto& pin_shape : pin->pin_shapes) { + auto intersections = shape_manager.findIntersections(pin_shape); + connect(v, intersections); + } + for (auto& via_cut : pin->via_cuts) { + auto intersections = shape_manager.findIntersections(via_cut); + connect(v, intersections); + } + } else { + LOG_FATAL << "Unknown content type"; + } + } +} +bool VecNetGraphGenerator::checkConnectivity(const TopoGraph& graph) const +{ + std::vector component(boost::num_vertices(graph)); + auto num = boost::connected_components(graph, component.data()); + if (num > 1) { + LOG_ERROR << "Topo Graph is not connected"; + // toQt(graph); + // toPy(graph, "/home/liweiguo/temp/file/temp_net.py"); + return false; + } + // toQt(graph); + // toPy(graph, "/home/liweiguo/temp/file/temp_net.py"); + return true; +} +WireGraph VecNetGraphGenerator::buildWireGraph(const TopoGraph& graph) const +{ + WireGraph wire_graph; + WireGraphVertexMap point_to_vertex; + auto build_and_connect = [&](const LayoutDefPoint& start, const LayoutDefPoint& end) -> void { + if (!point_to_vertex.contains(start)) { + auto vertex = boost::add_vertex(wire_graph); + wire_graph[vertex].x = getX(start); + wire_graph[vertex].y = getY(start); + wire_graph[vertex].layer_id = getZ(start); + point_to_vertex[start] = vertex; + } + if (!point_to_vertex.contains(end)) { + auto vertex = boost::add_vertex(wire_graph); + wire_graph[vertex].x = getX(end); + wire_graph[vertex].y = getY(end); + wire_graph[vertex].layer_id = getZ(end); + point_to_vertex[end] = vertex; + } + // check edge exists + auto start_vertex = point_to_vertex[start]; + auto end_vertex = point_to_vertex[end]; + if (boost::edge(start_vertex, end_vertex, wire_graph).second) { + return; + } + auto [edge, inserted] = boost::add_edge(start_vertex, end_vertex, wire_graph); + if (inserted) { + wire_graph[edge].path.emplace_back(std::make_pair(start, end)); + } + }; + // traversal all vertices + auto [v_iter, v_end] = boost::vertices(graph); + for (; v_iter != v_end; ++v_iter) { + auto v = *v_iter; + auto* content = graph[v].content; + if (content->is_patch()) { + continue; + } + if (content->is_wire()) { + auto* wire = static_cast(content); + build_and_connect(wire->start, wire->end); + } else if (content->is_via()) { + auto* via = static_cast(content); + auto cut_path = via->cut_path; + build_and_connect(cut_path.first, cut_path.second); + } else if (content->is_pin()) { + // only connect the pin's via cut + auto* pin = static_cast(content); + auto via_cuts = pin->via_cuts; + std::ranges::for_each(via_cuts, [&](const LayoutDefRect& via_cut) -> void { + auto center = getCenter(via_cut); + auto start = LayoutDefPoint(getX(center), getY(center), getZ(center) - 1); + auto end = LayoutDefPoint(getX(center), getY(center), getZ(center) + 1); + build_and_connect(start, end); + }); + } else { + LOG_FATAL << "Unknown content type"; + } + } + // post process + breakCycle(wire_graph); + innerConnectivityCompletion(graph, wire_graph, point_to_vertex); + buildVirtualWire(graph, wire_graph, point_to_vertex); + markPinVertex(graph, wire_graph); + reduceWireGraph(wire_graph); + checkConnectivity(wire_graph); + checkDriverIsTreeRoot(graph, wire_graph); + return wire_graph; +} +std::vector VecNetGraphGenerator::canonicalizeCycle(const std::vector& cycle) const +{ + auto forward = cycle; + auto backward = cycle; + std::reverse(backward.begin() + 1, backward.end()); + + return (forward < backward) ? forward : backward; +} +void VecNetGraphGenerator::dfsFindCycles(const WireGraph& graph, WireGraphVertex start, WireGraphVertex current, std::vector& visited, + std::vector& path, std::vector>& cycles) const +{ + for (auto neighbor : boost::make_iterator_range(adjacent_vertices(current, graph))) { + if (neighbor == start && path.size() >= 3) { + cycles.push_back(path); + } else if (!visited[neighbor] && neighbor > start) { + visited[neighbor] = true; + path.push_back(neighbor); + dfsFindCycles(graph, start, neighbor, visited, path, cycles); + path.pop_back(); + visited[neighbor] = false; + } + } +} +std::vector> VecNetGraphGenerator::findAllCycles(const WireGraph& graph) const +{ + std::vector> cycles; + const auto n = boost::num_vertices(graph); + std::vector visited(n, false); + + for (WireGraphVertex start = 0; start < n; ++start) { + visited[start] = true; + std::vector path; + path.push_back(start); + dfsFindCycles(graph, start, start, visited, path, cycles); + visited[start] = false; + } + std::ranges::for_each(cycles, [&](std::vector& cycle) -> void { cycle = canonicalizeCycle(cycle); }); + std::sort(cycles.begin(), cycles.end()); + cycles.erase(std::unique(cycles.begin(), cycles.end()), cycles.end()); + return cycles; +} +void VecNetGraphGenerator::breakCycle(WireGraph& graph) const +{ + if (!hasCycle(graph)) { + return; + } + // find all cycles, check cycle length whether is 4, and find the node which degree is 2, then remove one of nodes. + auto cycles = findAllCycles(graph); + std::ranges::for_each(cycles, [&](const std::vector& cycle) -> void { + LOG_FATAL_IF(cycle.size() != 4) << "Cycle length is " << cycle.size() << ", not 4"; + + auto degree_2_node + = std::find_if(cycle.begin(), cycle.end(), [&](const WireGraphVertex& v) -> bool { return boost::degree(v, graph) == 2; }); + LOG_FATAL_IF(degree_2_node == cycle.end()) << "No degree 2 node found"; + + auto v = *degree_2_node; + boost::clear_vertex(v, graph); + boost::remove_vertex(v, graph); + }); +} +void VecNetGraphGenerator::innerConnectivityCompletion(const TopoGraph& graph, WireGraph& wire_graph, + WireGraphVertexMap& point_to_vertex) const +{ + // Temporary structure to group the vertices by flatten shape + struct FlattenShape + { + int low_x; + int low_y; + int high_x; + int high_y; + + bool operator==(const FlattenShape& other) const + { + return low_x == other.low_x && low_y == other.low_y && high_x == other.high_x && high_y == other.high_y; + } + }; + + struct FlattenShapeHash + { + size_t operator()(const FlattenShape& shape) const + { + return std::hash()(shape.low_x) ^ std::hash()(shape.low_y) ^ std::hash()(shape.high_x) + ^ std::hash()(shape.high_y); + } + }; + + auto build_and_connect = [&](const LayoutDefPoint& start, const LayoutDefPoint& end) -> void { + if (!point_to_vertex.contains(start)) { + auto vertex = boost::add_vertex(wire_graph); + wire_graph[vertex].x = getX(start); + wire_graph[vertex].y = getY(start); + wire_graph[vertex].layer_id = getZ(start); + point_to_vertex[start] = vertex; + } + if (!point_to_vertex.contains(end)) { + auto vertex = boost::add_vertex(wire_graph); + wire_graph[vertex].x = getX(end); + wire_graph[vertex].y = getY(end); + wire_graph[vertex].layer_id = getZ(end); + point_to_vertex[end] = vertex; + } + // check edge exists + auto start_vertex = point_to_vertex[start]; + auto end_vertex = point_to_vertex[end]; + if (boost::edge(start_vertex, end_vertex, wire_graph).second) { + return; + } + auto [edge, inserted] = boost::add_edge(start_vertex, end_vertex, wire_graph); + if (inserted) { + wire_graph[edge].path.emplace_back(std::make_pair(start, end)); + } + }; + // Build an R-tree to locate points within a shape + LayoutShapeManager shape_manager; + std::vector points; + for (auto& [point, vertex] : point_to_vertex) { + points.emplace_back(point); + } + for (size_t i = 0; i < points.size(); ++i) { + shape_manager.addShape(points[i], i); + } + + auto connectivity_complete = [&](const TopoGraphVertex& v) -> void { + auto* content = graph[v].content; + if (!content->is_pin()) { + return; + } + auto* pin = static_cast(content); + auto pin_shapes = pin->pin_shapes; + auto via_cuts = pin->via_cuts; + auto via_cuts_set = std::unordered_set(via_cuts.begin(), via_cuts.end()); + // Group pin shapes by (low_x, low_y, high_x, high_y), if the group has more than one shape, connect them + std::unordered_map, FlattenShapeHash> shape_map; + for (size_t i = 0; i < pin_shapes.size(); ++i) { + auto& shape = pin_shapes[i]; + auto low_x = getLowX(shape); + auto low_y = getLowY(shape); + auto high_x = getHighX(shape); + auto high_y = getHighY(shape); + shape_map[{low_x, low_y, high_x, high_y}].emplace_back(i); + } + // Check if the group has more than one shape, if so, further check the connectivity between the neighboring shapes + for (auto& [shape, indices] : shape_map) { + if (indices.size() < 2) { + continue; + } + std::vector flatten_shapes; + std::ranges::transform(indices, std::back_inserter(flatten_shapes), [&](size_t i) -> LayoutDefRect { return pin_shapes[i]; }); + // sort the shapes by layer, ascending + std::ranges::sort(flatten_shapes, + [&](const LayoutDefRect& lhs, const LayoutDefRect& rhs) -> bool { return getLowZ(lhs) < getLowZ(rhs); }); + // connect the neighboring shapes + for (size_t i = 0; i < flatten_shapes.size() - 1; ++i) { + auto low_shape = flatten_shapes[i]; + auto high_shape = flatten_shapes[i + 1]; + + auto low_point_ids = shape_manager.findIntersections(low_shape); + auto high_points = shape_manager.findIntersections(high_shape); + + if (low_point_ids.empty() || high_points.empty()) { + continue; + } + + std::ranges::for_each(low_point_ids, [&](size_t low_id) -> void { + auto low_point = points[low_id]; + auto high_point = LayoutDefPoint(getX(low_point), getY(low_point), getHighZ(high_shape)); + auto via_cut = LayoutDefRect(low_point, high_point); + if (via_cuts_set.find(via_cut) != via_cuts_set.end()) { + return; + } + via_cuts_set.insert(via_cut); + build_and_connect(low_point, high_point); + }); + continue; + } + } + // Update the pin's via cuts + pin->via_cuts = std::vector(via_cuts_set.begin(), via_cuts_set.end()); + }; + // Traverse all vertices + auto [v_iter, v_end] = boost::vertices(graph); + for (; v_iter != v_end; ++v_iter) { + auto v = *v_iter; + connectivity_complete(v); + } +} +void VecNetGraphGenerator::buildVirtualWire(const TopoGraph& graph, WireGraph& wire_graph, WireGraphVertexMap& point_to_vertex) const +{ + // for each pin and patch in TopoGraph + std::vector pins_to_process; + std::vector patches_to_process; + auto [v_iter, v_end] = boost::vertices(graph); + for (; v_iter != v_end; ++v_iter) { + auto v = *v_iter; + auto* content = graph[v].content; + auto [neighbors_begin, neighbors_end] = boost::adjacent_vertices(v, graph); + size_t count = 0; + for (auto it = neighbors_begin; it != neighbors_end; ++it) { + auto neighbor = *it; + if (graph[neighbor].content->is_wire() || graph[neighbor].content->is_via()) { + ++count; + } + } + if (content->is_pin()) { + auto* pin = static_cast(content); + count += pin->via_cuts.size(); + if (count > 1) { + pins_to_process.emplace_back(v); + } + } + if (content->is_patch() && count > 1) { + patches_to_process.emplace_back(v); + } + } + if (pins_to_process.empty() && patches_to_process.empty()) { + return; + } + // if (!patches_to_process.empty()) { + // LOG_WARNING << "Patch is not supported"; + // } + // PIN PROCESS + std::ranges::for_each(pins_to_process, [&](TopoGraphVertex v) -> void { + auto* content = graph[v].content; + auto* pin = static_cast(content); + // only save the points in the shapes + auto shape_manager = LayoutShapeManager(); + for (size_t i = 0; i < pin->pin_shapes.size(); ++i) { + shape_manager.addShape(pin->pin_shapes[i], i); + } + auto is_in_shapes = [&](const LayoutDefPoint& point) -> bool { + auto intersections = shape_manager.findIntersections(point); + return !intersections.empty(); + }; + // divide pin's shape by layer + std::unordered_map> shapes_by_layer; + for (auto& pin_shape : pin->pin_shapes) { + shapes_by_layer[getLowZ(pin_shape)].emplace_back(pin_shape); + } + // divide via cuts, pin's via cuts and wire's end points by layer + std::unordered_map> connections_by_layer; + auto [neighbors_begin, neighbors_end] = boost::adjacent_vertices(v, graph); + for (auto it = neighbors_begin; it != neighbors_end; ++it) { + auto neighbor = *it; + auto* neighbor_content = graph[neighbor].content; + if (neighbor_content->is_wire()) { + auto* wire = static_cast(neighbor_content); + auto start = LayoutDefPoint(wire->start); + auto end = LayoutDefPoint(wire->end); + if (is_in_shapes(start)) { + connections_by_layer[getZ(start)].emplace_back(start); + } + if (is_in_shapes(end)) { + connections_by_layer[getZ(end)].emplace_back(end); + } + } else if (neighbor_content->is_via()) { + auto* via = static_cast(neighbor_content); + auto cut_path = via->cut_path; + auto start = cut_path.first; + auto end = cut_path.second; + if (is_in_shapes(start)) { + connections_by_layer[getZ(start)].emplace_back(start); + } + if (is_in_shapes(end)) { + connections_by_layer[getZ(end)].emplace_back(end); + } + } + } + // pin's via cuts + for (auto& via_cut : pin->via_cuts) { + auto center = getCenter(via_cut); + auto start = LayoutDefPoint(getX(center), getY(center), getZ(center) - 1); + auto end = LayoutDefPoint(getX(center), getY(center), getZ(center) + 1); + connections_by_layer[getZ(center) - 1].emplace_back(start); + connections_by_layer[getZ(center) + 1].emplace_back(end); + } + // for each layer, generate connected points + auto drop_duplicate = [&](const std::vector& points) -> std::vector { + std::unordered_set point_set; + std::ranges::copy_if(points, std::inserter(point_set, point_set.end()), + [&](const LayoutDefPoint& point) -> bool { return point_set.find(point) == point_set.end(); }); + return std::vector(point_set.begin(), point_set.end()); + }; + for (auto& [layer_id, shapes] : shapes_by_layer) { + auto& connections = connections_by_layer[layer_id]; + connections = drop_duplicate(connections); + if (connections.size() < 2) { + continue; + } + auto paths = generateShortestPath(connections, shapes); + std::ranges::for_each(paths, [&](const std::vector& path) -> void { + // add to wrie graph + auto start = path.front(); + auto end = path.back(); + std::vector> path_pairs; + for (size_t i = 0; i < path.size() - 1; ++i) { + path_pairs.emplace_back(std::make_pair(path[i], path[i + 1])); + } + auto start_vertex = point_to_vertex[start]; + auto end_vertex = point_to_vertex[end]; + if (boost::edge(start_vertex, end_vertex, wire_graph).second) { + return; + } + auto [edge, inserted] = boost::add_edge(start_vertex, end_vertex, wire_graph); + if (inserted) { + wire_graph[edge].path = path_pairs; + } + }); + } + }); +} +void VecNetGraphGenerator::markPinVertex(const TopoGraph& graph, WireGraph& wire_graph) const +{ + auto shape_manager = LayoutShapeManager(); + auto [v_topo_iter, v_topo_end] = boost::vertices(graph); + for (; v_topo_iter != v_topo_end; ++v_topo_iter) { + auto v = *v_topo_iter; + auto* content = graph[v].content; + if (content->is_pin()) { + auto* pin = static_cast(content); + for (auto& pin_shape : pin->pin_shapes) { + shape_manager.addShape(pin_shape, v); + } + } + } + // for each node in wire graph, if it's located in the pin shape, mark it as pin + auto [v_wire_iter, v_wire_end] = boost::vertices(wire_graph); + for (; v_wire_iter != v_wire_end; ++v_wire_iter) { + auto v = *v_wire_iter; + auto x = wire_graph[v].x; + auto y = wire_graph[v].y; + auto layer_id = wire_graph[v].layer_id; + auto point = LayoutDefPoint(x, y, layer_id); + auto intersections = shape_manager.findIntersections(point); + if (intersections.empty()) { + continue; + } + auto is_driver_pin = std::ranges::any_of(intersections, [&](size_t i) -> bool { + auto* content = graph[i].content; + if (content->is_pin()) { + auto* pin = static_cast(content); + return pin->is_driver_pin; + } + return false; + }); + wire_graph[v].is_pin = true; + wire_graph[v].is_driver_pin = is_driver_pin; + } +} +void VecNetGraphGenerator::reduceWireGraph(WireGraph& graph, const bool& retain_pin) const +{ + // Step 1: Prepare + + size_t num_vertices = boost::num_vertices(graph); + std::vector visited(num_vertices, false); + + auto is_reduce_vertex = [&](WireGraphVertex v) -> bool { + if (boost::degree(v, graph) != 2) { + return false; + } + auto neighbors = boost::adjacent_vertices(v, graph); + auto left = *neighbors.first; + auto right = *std::next(neighbors.first); + return graph[v].layer_id == graph[left].layer_id && graph[v].layer_id == graph[right].layer_id; + }; + + // Step 2: Start from an endpoint with degree 1 and collect a sub-path + struct PathToReduce + { + std::vector vertices; + }; + + std::vector paths_to_reduce; + WireGraphVertex start_vertex = 0; + for (size_t i = 0; i < num_vertices; ++i) { + if (boost::degree(i, graph) == 1) { + start_vertex = i; + break; + } + } + + // Step 3: DFS from the start vertex + std::stack stack; + stack.push(start_vertex); + while (!stack.empty()) { + WireGraphVertex current = stack.top(); + stack.pop(); + visited[current] = true; + + auto [adj_iter_begin, adj_iter_end] = boost::adjacent_vertices(current, graph); + for (auto it = adj_iter_begin; it != adj_iter_end; ++it) { + WireGraphVertex v = *it; + if (!visited[v] && is_reduce_vertex(v)) { + PathToReduce path; + path.vertices.emplace_back(current); + path.vertices.emplace_back(v); + while (is_reduce_vertex(v)) { + visited[v] = true; + auto neighbors = boost::adjacent_vertices(v, graph); + auto left = *neighbors.first; + auto right = *std::next(neighbors.first); + if (!visited[left]) { + path.vertices.emplace_back(left); + v = left; + } else if (!visited[right]) { + path.vertices.emplace_back(right); + v = right; + } else { + LOG_ERROR << "Cannot find a valid path to reduce"; + break; + } + } + paths_to_reduce.emplace_back(path); + stack.push(v); + } else if (!visited[v]) { + stack.push(v); + } + } + } + + // Step 4: Remove the paths which include virtual wires + if (retain_pin) { + std::erase_if(paths_to_reduce, [&](const PathToReduce& path) -> bool { + for (size_t i = 0; i < path.vertices.size(); ++i) { + auto v = path.vertices[i]; + if (graph[v].is_pin) { + return true; + } + } + return false; + }); + } + + // Step 5: Reduce the paths + for (const auto& path : paths_to_reduce) { + auto vertices = path.vertices; + if (vertices.size() < 3) { + continue; + } + auto start = vertices.front(); + auto end = vertices.back(); + // add edge between start and end + auto [edge, inserted] = boost::add_edge(start, end, graph); + if (inserted) { + auto& new_path = graph[edge].path; + new_path.clear(); + for (size_t i = 0; i < vertices.size() - 1; ++i) { + auto cur = vertices[i]; + auto next = vertices[i + 1]; + auto cur_edge = boost::edge(cur, next, graph).first; + auto& path = graph[cur_edge].path; + auto cur_point = LayoutDefPoint(graph[cur].x, graph[cur].y, graph[cur].layer_id); + auto path_start_point = path.front().first; + if (bg::equals(cur_point, path_start_point)) { + new_path.insert(new_path.end(), path.begin(), path.end()); + } else { + // swap for each pair + auto reverse_path = path; + std::ranges::reverse(reverse_path); + std::ranges::for_each(reverse_path, [&](const std::pair& pair) -> void { + new_path.emplace_back(std::make_pair(pair.second, pair.first)); + }); + } + } + } + } + std::vector vertices_to_remove; + std::ranges::for_each(paths_to_reduce, [&](const PathToReduce& path) -> void { + vertices_to_remove.insert(vertices_to_remove.end(), path.vertices.begin() + 1, path.vertices.end() - 1); + }); + std::ranges::sort(vertices_to_remove, std::greater<>()); + std::ranges::for_each(vertices_to_remove, [&](WireGraphVertex v) -> void { + boost::clear_vertex(v, graph); + boost::remove_vertex(v, graph); + }); + + // Step 6: Reduce the redundant path pairs (with the same direction) + auto calc_direction = [&](const LayoutDefPoint& start, const LayoutDefPoint& end) -> int { + if (getX(start) == getX(end)) { + return getY(start) < getY(end) ? 0 : 1; + } else { + return getX(start) < getX(end) ? 2 : 3; + } + }; + auto remove_redundant_path = [&](std::vector>& path) -> void { + if (path.size() < 2) { + return; + } + std::vector> new_path; + + auto it = path.begin(); + while (it != path.end()) { + auto start = it->first; + auto end = it->second; + auto direction = calc_direction(start, end); + + auto next = std::next(it); + while (next != path.end() && calc_direction(end, next->second) == direction) { + end = next->second; + ++next; + } + + new_path.emplace_back(start, end); + + it = next; + } + + path = std::move(new_path); + }; + auto [e_iter, e_end] = boost::edges(graph); + for (; e_iter != e_end; ++e_iter) { + auto e = *e_iter; + auto& path = graph[e].path; + if (path.size() < 2) { + continue; + } + remove_redundant_path(path); + } +} + +// Helper function to check for cycles in the graph +bool VecNetGraphGenerator::hasCycleUtil(const WireGraph& graph, WireGraphVertex v, std::vector& visited, WireGraphVertex parent) const +{ + visited[v] = true; + + auto [adj_iter_begin, adj_iter_end] = boost::adjacent_vertices(v, graph); + for (auto it = adj_iter_begin; it != adj_iter_end; ++it) { + WireGraphVertex adj_v = *it; + if (!visited[adj_v]) { + if (hasCycleUtil(graph, adj_v, visited, v)) + return true; + } else if (adj_v != parent) { + return true; + } + } + return false; +} + +bool VecNetGraphGenerator::hasCycle(const WireGraph& graph) const +{ + size_t num_vertices = boost::num_vertices(graph); + std::vector visited(num_vertices, false); + + for (size_t i = 0; i < num_vertices; ++i) { + if (!visited[i]) { + if (hasCycleUtil(graph, i, visited, -1)) + return true; + } + } + return false; +} +bool VecNetGraphGenerator::checkConnectivity(const WireGraph& graph) const +{ + std::vector component(boost::num_vertices(graph)); + auto num = boost::connected_components(graph, component.data()); + if (num > 1) { + LOG_ERROR << "Wire Graph is not connected"; + // toQt(graph); + // toPy(graph, "/home/liweiguo/temp/file/temp_net.py"); + return false; + } + // toQt(graph); + // toPy(graph, "/home/liweiguo/temp/file/temp_net.py"); + return true; +} +bool VecNetGraphGenerator::checkDriverIsTreeRoot(const TopoGraph& topo_graph, const WireGraph& wire_graph) const +{ + // build rtree for driver pin shapes + auto shape_manager = LayoutShapeManager(); + auto [v_iter, v_end] = boost::vertices(topo_graph); + for (; v_iter != v_end; ++v_iter) { + auto v = *v_iter; + auto* content = topo_graph[v].content; + if (content->is_pin()) { + auto* pin = static_cast(content); + if (!pin->is_driver_pin) { + continue; + } + auto pin_shapes = pin->pin_shapes; + for (size_t i = 0; i < pin_shapes.size(); ++i) { + shape_manager.addShape(pin_shapes[i], i); + } + } + } + // check leaf vertices in wire graph whether is in the driver pin shapes + size_t connected_point_count = 0; + auto [w_iter, w_end] = boost::vertices(wire_graph); + for (; w_iter != w_end; ++w_iter) { + auto v = *w_iter; + auto x = wire_graph[v].x; + auto y = wire_graph[v].y; + auto layer_id = wire_graph[v].layer_id; + auto point = LayoutDefPoint(x, y, layer_id); + auto intersections = shape_manager.findIntersections(point); + if (intersections.empty()) { + continue; + } + ++connected_point_count; + } + if (connected_point_count > 1) { + // LOG_ERROR << "Multiple connections to driver pin are not allowed, please check the design"; + // toPy(topo_graph, "/home/liweiguo/temp/file/temp_topo.py"); + // toPy(wire_graph, "/home/liweiguo/temp/file/temp_wire.py"); + return false; + } + return true; +} +std::vector> VecNetGraphGenerator::generateShortestPath(const std::vector& points, + const std::vector& regions) const +{ + using PointSet = std::unordered_set; + PointSet path_point_set(points.begin(), points.end()); + + auto shape_manager = LayoutShapeManager(); + for (size_t i = 0; i < regions.size(); ++i) { + shape_manager.addShape(regions[i], i); + } + + // 1. generate seg pivot between regions + std::ranges::for_each(regions, [&](const LayoutDefRect& rect) -> void { + auto intersections = shape_manager.findIntersections(rect); + std::vector segs; + std::ranges::for_each(intersections, [&](const size_t& idx) -> void { + auto other = regions[idx]; + if (boost::geometry::equals(rect, other)) { + return; + } + if (!bg::intersects(rect, other)) { + return; + } + LayoutDefSeg seg; + bg::intersection(rect, other, seg); + segs.emplace_back(seg); + }); + std::ranges::for_each(segs, [&](const LayoutDefSeg& seg) -> void { + auto pivot = generateSegPivot(seg, rect); + path_point_set.insert(pivot); + }); + }); + + // 2. generate crossroads points between points and regions + PointSet add_point_set; + std::ranges::for_each(points, [&](const LayoutDefPoint& point) -> void { + auto intersections = shape_manager.findIntersections(point); + std::ranges::for_each(intersections, [&](const size_t& idx) -> void { + auto rect = regions[idx]; + auto crossroads = generateCrossroadsPoints(point, rect); + std::ranges::for_each(crossroads, [&](const LayoutDefPoint& crossroad) -> void { add_point_set.insert(crossroad); }); + }); + }); + std::ranges::for_each(add_point_set, [&](const LayoutDefPoint& point) -> void { + auto intersections = shape_manager.findIntersections(point); + std::ranges::for_each(intersections, [&](const size_t& idx) -> void { + auto rect = regions[idx]; + auto pivot = generatePointPivot(point, rect); + path_point_set.insert(pivot); + }); + }); + + auto path_point_vec = std::vector(path_point_set.begin(), path_point_set.end()); + // 3. generate shortest path which connects all input {points} + auto paths = findByDijkstra(points, path_point_vec, regions); + return paths; +} +std::vector> VecNetGraphGenerator::findByDijkstra(const std::vector& points, + const std::vector& path_points, + const std::vector& regions) const +{ + // pre-process + using FlatPoint = bg::model::point; + using FlatLine = bg::model::linestring; + using FlatPolygon = bg::model::polygon; + using FlatMultiPolygon = bg::model::multi_polygon; + FlatMultiPolygon regions_polygon; + + std::ranges::for_each(regions, [&](const LayoutDefRect& rect) -> void { + FlatPolygon polygon; + bg::append(polygon.outer(), FlatPoint(getLowX(rect), getLowY(rect))); + bg::append(polygon.outer(), FlatPoint(getHighX(rect), getLowY(rect))); + bg::append(polygon.outer(), FlatPoint(getHighX(rect), getHighY(rect))); + bg::append(polygon.outer(), FlatPoint(getLowX(rect), getHighY(rect))); + bg::correct(polygon); + + std::vector regions_polygon_list; + bg::union_(regions_polygon, polygon, regions_polygon_list); + + regions_polygon.clear(); + std::ranges::for_each(regions_polygon_list, [&](const FlatPolygon& poly) -> void { regions_polygon.emplace_back(poly); }); + }); + + struct GridGraphVertexProperty + { + LayoutDefPoint point; + }; + struct GridGraphEdgeProperty + { + int weight; + }; + using GridGraph = boost::adjacency_list; + using GridGraphVertex = boost::graph_traits::vertex_descriptor; + using GridVertexMap = std::unordered_map; + GridGraph grid; + GridVertexMap point_to_vertex; + auto build_and_connect = [&](const LayoutDefPoint& start, const LayoutDefPoint& end) -> void { + if (!point_to_vertex.contains(start)) { + auto vertex = boost::add_vertex(grid); + grid[vertex].point = start; + point_to_vertex[start] = vertex; + } + if (!point_to_vertex.contains(end)) { + auto vertex = boost::add_vertex(grid); + grid[vertex].point = end; + point_to_vertex[end] = vertex; + } + // check edge exists + auto start_vertex = point_to_vertex[start]; + auto end_vertex = point_to_vertex[end]; + if (boost::edge(start_vertex, end_vertex, grid).second) { + return; + } + auto [edge, inserted] = boost::add_edge(start_vertex, end_vertex, grid); + if (inserted) { + grid[edge].weight = std::abs(getX(start) - getX(end)) + std::abs(getY(start) - getY(end)); + } + }; + // build edges between path_points in path_point_set (if e(p1, p2) is vertical or horizontal, and e(p1, p2) is in the regions) + for (size_t i = 0; i < path_points.size(); ++i) { + for (size_t j = i + 1; j < path_points.size(); ++j) { + auto p1 = path_points[i]; + auto p2 = path_points[j]; + if (getX(p1) == getX(p2) || getY(p1) == getY(p2)) { + FlatLine flat_line; + bg::append(flat_line, FlatPoint(getX(p1), getY(p1))); + bg::append(flat_line, FlatPoint(getX(p2), getY(p2))); + if (!bg::covered_by(flat_line, regions_polygon)) { + continue; + } + build_and_connect(p1, p2); + } + } + } + // 1. find shortest path between points, by Dijkstra (distance is edge weight) + auto weight_map = boost::get(&GridGraphEdgeProperty::weight, grid); + auto find_shortest_path = [&](const LayoutDefPoint& start, const LayoutDefPoint& end) -> std::vector { + auto start_vertex = point_to_vertex[start]; + auto end_vertex = point_to_vertex[end]; + std::vector predecessors(boost::num_vertices(grid)); + std::vector distances(boost::num_vertices(grid)); + boost::dijkstra_shortest_paths(grid, start_vertex, + boost::predecessor_map(predecessors.data()).distance_map(distances.data()).weight_map(weight_map)); + std::vector path; + for (auto v = end_vertex; v != start_vertex; v = predecessors[v]) { + path.emplace_back(grid[v].point); + } + path.emplace_back(start); + std::reverse(path.begin(), path.end()); + return path; + }; + auto calc_distance = [&](const std::vector& path) -> int { + int distance = 0; + for (size_t i = 0; i < path.size() - 1; ++i) { + distance += std::abs(getX(path[i]) - getX(path[i + 1])) + std::abs(getY(path[i]) - getY(path[i + 1])); + } + return distance; + }; + // 2. build points graph by shortest distance (for find the minimum spanning tree/path) + using PointGraph + = boost::adjacency_list>; + using PointGraphEdge = boost::graph_traits::edge_descriptor; + PointGraph point_graph; + for (size_t i = 0; i < points.size(); ++i) { + for (size_t j = i + 1; j < points.size(); ++j) { + auto p1 = points[i]; + auto p2 = points[j]; + auto path = find_shortest_path(p1, p2); + auto distance = calc_distance(path); + auto [edge, inserted] = boost::add_edge(i, j, point_graph); + if (inserted) { + boost::put(boost::edge_weight, point_graph, edge, distance); + } + } + } + // 3. find the minimum spanning tree/path by Kruskal + std::vector spanning_tree; + boost::kruskal_minimum_spanning_tree(point_graph, std::back_inserter(spanning_tree)); + // 4. check if the spanning tree is a path, and convert it to the path + std::vector> paths; + std::ranges::for_each(spanning_tree, [&](PointGraphEdge edge) -> void { + auto start = points[boost::source(edge, point_graph)]; + auto end = points[boost::target(edge, point_graph)]; + auto path = find_shortest_path(start, end); + paths.emplace_back(path); + }); + return paths; +} +std::vector VecNetGraphGenerator::generateCrossroadsPoints(const LayoutDefPoint& p, const LayoutDefRect& rect) const +{ + std::unordered_set points; + auto x = getX(p); + auto y = getY(p); + auto z = getZ(p); + auto low_x = getLowX(rect); + auto high_x = getHighX(rect); + auto low_y = getLowY(rect); + auto high_y = getHighY(rect); + points.insert(LayoutDefPoint(x, low_y, z)); + points.insert(LayoutDefPoint(x, high_y, z)); + points.insert(LayoutDefPoint(low_x, y, z)); + points.insert(LayoutDefPoint(high_x, y, z)); + return std::vector(points.begin(), points.end()); +} +LayoutDefPoint VecNetGraphGenerator::generatePointPivot(const LayoutDefPoint& p, const LayoutDefRect& rect) const +{ + auto x = getX(p); + auto y = getY(p); + auto z = getZ(p); + auto low_x = getLowX(rect); + auto high_x = getHighX(rect); + auto low_y = getLowY(rect); + auto high_y = getHighY(rect); + if (x == low_x || x == high_x) { + auto new_x = (low_x + high_x) / 2; + return LayoutDefPoint(new_x, y, z); + } + if (y == low_y || y == high_y) { + auto new_y = (low_y + high_y) / 2; + return LayoutDefPoint(x, new_y, z); + } + LOG_FATAL << "Invalid point pivot"; + return LayoutDefPoint(); +} +LayoutDefPoint VecNetGraphGenerator::generateSegPivot(const LayoutDefSeg& seg, const LayoutDefRect& rect) const +{ + LayoutDefPoint center = getCenter(seg); + return generatePointPivot(center, rect); +} +void VecNetGraphGenerator::toPy(const TopoGraph& graph, const std::string& path) const +{ + std::ofstream file(path); + file << "import plotly.graph_objects as go\n"; + file << "import matplotlib.cm as cm\n"; + file << "\n"; + file << "# Create a Plotly Figure\n"; + file << "fig = go.Figure()\n"; + file << "\n"; + size_t patch_count = 0; + size_t wire_count = 0; + size_t via_count = 0; + size_t pin_count = 0; + std::vector component(boost::num_vertices(graph)); + auto num_components = boost::connected_components(graph, component.data()); + file << "colors = [f'rgb{cm.tab10(i)[:3]}' for i in range(" << num_components << ")]\n"; + auto [v_iter, v_end] = boost::vertices(graph); + for (; v_iter != v_end; ++v_iter) { + auto v = *v_iter; + auto* content = graph[v].content; + if (content->is_patch()) { + auto* patch = static_cast(content); + // plot rect + file << "fig.add_trace(go.Scatter3d(\n"; + file << " x=[" << getLowX(patch->rect) << ", " << getHighX(patch->rect) << ", " << getHighX(patch->rect) << ", " + << getLowX(patch->rect) << ", " << getLowX(patch->rect) << "],\n"; + file << " y=[" << getLowY(patch->rect) << ", " << getLowY(patch->rect) << ", " << getHighY(patch->rect) << ", " + << getHighY(patch->rect) << ", " << getLowY(patch->rect) << "],\n"; + file << " z=[" << getLowZ(patch->rect) << ", " << getLowZ(patch->rect) << ", " << getLowZ(patch->rect) << ", " + << getLowZ(patch->rect) << ", " << getLowZ(patch->rect) << "],\n"; + file << " mode='lines',\n"; + file << " line=dict(color='rgb(0,128,0)', width=4),\n"; + file << " name='Patch " << patch_count++ << "'\n"; + file << "))\n"; + } else if (content->is_wire()) { + auto* wire = static_cast(content); + // plot line + file << "fig.add_trace(go.Scatter3d(\n"; + file << " x=[" << getX(wire->start) << ", " << getX(wire->end) << "],\n"; + file << " y=[" << getY(wire->start) << ", " << getY(wire->end) << "],\n"; + file << " z=[" << getZ(wire->start) << ", " << getZ(wire->end) << "],\n"; + file << " mode='lines',\n"; + file << " line=dict(color=colors[" << component[v] << "], width=4),\n"; + file << " name='Wire " << wire_count++ << "'\n"; + file << "))\n"; + } else if (content->is_via()) { + auto* via = static_cast(content); + size_t bottom_count = 0; + size_t top_count = 0; + // plot cut path + file << "fig.add_trace(go.Scatter3d(\n"; + file << " x=[" << getStartX(via->cut_path) << ", " << getEndX(via->cut_path) << "],\n"; + file << " y=[" << getStartY(via->cut_path) << ", " << getEndY(via->cut_path) << "],\n"; + file << " z=[" << getStartZ(via->cut_path) << ", " << getEndZ(via->cut_path) << "],\n"; + file << " mode='lines',\n"; + file << " line=dict(color=colors[" << component[v] << "], width=4),\n"; + file << " name='Via " << via_count << " Cut Path'\n"; + file << "))\n"; + for (auto& bottom_shape : via->bottom_shapes) { + // plot bottom shapes + file << "fig.add_trace(go.Scatter3d(\n"; + file << " x=[" << getLowX(bottom_shape) << ", " << getHighX(bottom_shape) << ", " << getHighX(bottom_shape) << ", " + << getLowX(bottom_shape) << ", " << getLowX(bottom_shape) << "],\n"; + file << " y=[" << getLowY(bottom_shape) << ", " << getLowY(bottom_shape) << ", " << getHighY(bottom_shape) << ", " + << getHighY(bottom_shape) << ", " << getLowY(bottom_shape) << "],\n"; + file << " z=[" << getLowZ(bottom_shape) << ", " << getLowZ(bottom_shape) << ", " << getLowZ(bottom_shape) << ", " + << getLowZ(bottom_shape) << ", " << getLowZ(bottom_shape) << "],\n"; + file << " mode='lines',\n"; + file << " line=dict(color='rgb(128,128,128)', width=4),\n"; + file << " name='Via " << via_count << " Bottom " << bottom_count++ << "'\n"; + file << "))\n"; + } + for (auto& top_shape : via->top_shapes) { + // plot top shapes + file << "fig.add_trace(go.Scatter3d(\n"; + file << " x=[" << getLowX(top_shape) << ", " << getHighX(top_shape) << ", " << getHighX(top_shape) << ", " << getLowX(top_shape) + << ", " << getLowX(top_shape) << "],\n"; + file << " y=[" << getLowY(top_shape) << ", " << getLowY(top_shape) << ", " << getHighY(top_shape) << ", " << getHighY(top_shape) + << ", " << getLowY(top_shape) << "],\n"; + file << " z=[" << getLowZ(top_shape) << ", " << getLowZ(top_shape) << ", " << getLowZ(top_shape) << ", " << getLowZ(top_shape) + << ", " << getLowZ(top_shape) << "],\n"; + file << " mode='lines',\n"; + file << " line=dict(color='rgb(128,128,128)', width=4),\n"; + file << " name='Via " << via_count << " Top " << top_count++ << "'\n"; + file << "))\n"; + } + via_count++; + } else if (content->is_pin()) { + auto* pin = static_cast(content); + size_t via_pin_shape_count = 0; + size_t via_cut_count = 0; + auto pin_name = pin->net_name + "/" + pin->pin_name; + auto rgb_color = pin->is_driver_pin ? "rgb(255,0,0)" : "rgb(255, 255, 0)"; + for (auto& pin_shape : pin->pin_shapes) { + // plot pin shapes + file << "fig.add_trace(go.Scatter3d(\n"; + file << " x=[" << getLowX(pin_shape) << ", " << getHighX(pin_shape) << ", " << getHighX(pin_shape) << ", " << getLowX(pin_shape) + << ", " << getLowX(pin_shape) << "],\n"; + file << " y=[" << getLowY(pin_shape) << ", " << getLowY(pin_shape) << ", " << getHighY(pin_shape) << ", " << getHighY(pin_shape) + << ", " << getLowY(pin_shape) << "],\n"; + file << " z=[" << getLowZ(pin_shape) << ", " << getLowZ(pin_shape) << ", " << getLowZ(pin_shape) << ", " << getLowZ(pin_shape) + << ", " << getLowZ(pin_shape) << "],\n"; + file << " mode='lines',\n"; + file << " line=dict(color='" << rgb_color << "', width=4),\n"; + file << " name='Pin " << pin_name << " Id " << pin_count << " Shape " << via_pin_shape_count++ << "'\n"; + file << "))\n"; + } + + for (auto& via_cut : pin->via_cuts) { + auto center = getCenter(via_cut); + // plot line + file << "fig.add_trace(go.Scatter3d(\n"; + file << " x=[" << getX(center) << ", " << getX(center) << "],\n"; + file << " y=[" << getY(center) << ", " << getY(center) << "],\n"; + file << " z=[" << getLowZ(via_cut) << ", " << getHighZ(via_cut) << "],\n"; + file << " mode='lines',\n"; + file << " line=dict(color='" << rgb_color << "', width=4),\n"; + file << " name='Pin " << pin_name << " Id " << pin_count << " Via Cut " << via_cut_count++ << "'\n"; + file << "))\n"; + } + pin_count++; + } + } + // Set up the layout with axis labels and title + file << "\n"; + file << "fig.update_layout(\n"; + file << " scene=dict(\n"; + file << " xaxis_title='X',\n"; + file << " yaxis_title='Y',\n"; + file << " zaxis_title='Layer ID'\n"; + file << " ),\n"; + file << " title='Temp Net'\n"; + file << ")\n"; + file << "\n"; + + // Show the plot + file << "fig.show()\n"; +} +void VecNetGraphGenerator::toPy(const WireGraph& graph, const std::string& path) const +{ + std::ofstream file(path); + file << "import plotly.graph_objects as go\n"; + file << "import matplotlib.cm as cm\n"; + file << "\n"; + file << "# Create a Plotly Figure\n"; + file << "fig = go.Figure()\n"; + file << "\n"; + std::vector component(boost::num_vertices(graph)); + auto num_components = boost::connected_components(graph, component.data()); + file << "colors = [f'rgb{cm.tab10(i)[:3]}' for i in range(" << num_components << ")]\n"; + size_t wire_idx = 0; + size_t via_idx = 0; + auto [e_iter, e_end] = boost::edges(graph); + for (; e_iter != e_end; ++e_iter) { + auto e = *e_iter; + auto u = boost::source(e, graph); + auto v = boost::target(e, graph); + size_t path_idx = 0; + // plot line + for (const auto& [start, end] : graph[e].path) { + file << "fig.add_trace(go.Scatter3d(\n"; + file << " x=[" << getX(start) << ", " << getX(end) << "],\n"; + file << " y=[" << getY(start) << ", " << getY(end) << "],\n"; + file << " z=[" << getZ(start) << ", " << getZ(end) << "],\n"; + file << " mode='lines',\n"; + file << " line=dict(color=colors[" << component[u] << "], width=4),\n"; + if (graph[u].layer_id == graph[v].layer_id) { + file << " name='Component " << component[u] << ", Wire " << wire_idx << ", Path " << path_idx++ << "'\n"; + } else { + file << " name='Component " << component[u] << ", Via " << via_idx << "'\n"; + } + file << "))\n"; + } + if (graph[u].layer_id == graph[v].layer_id) { + wire_idx++; + } else { + via_idx++; + } + } + + // Set up the layout with axis labels and title + file << "\n"; + file << "fig.update_layout(\n"; + file << " scene=dict(\n"; + file << " xaxis_title='X',\n"; + file << " yaxis_title='Y',\n"; + file << " zaxis_title='Layer ID'\n"; + file << " ),\n"; + file << " title='Temp Net'\n"; + file << ")\n"; + file << "\n"; + + // Show the plot + file << "fig.show()\n"; +} +void VecNetGraphGenerator::toQt(const TopoGraph& graph, const bool& component_mode) const +{ + // Create the Qt application if needed (assumes one is not already running) +#ifdef BUILD_VEC_GUI + int argc = 0; + char** argv = nullptr; + auto app = QApplication(argc, argv); + + // Create the widget. + VecGraphWidget* widget = new VecGraphWidget(); + + // Compute connected components for color selection if needed. + std::vector component(boost::num_vertices(graph)); + + size_t patch_count = 0; + size_t wire_count = 0; + size_t via_count = 0; + size_t pin_count = 0; + + auto [v_iter, v_end] = boost::vertices(graph); + for (; v_iter != v_end; ++v_iter) { + auto v = *v_iter; + auto* content = graph[v].content; + if (content->is_patch()) { + auto* patch = static_cast(content); + // Add patch as a rectangle (default green). + auto label = component_mode ? "Component " + std::to_string(component[v]) : "Patch"; + widget->addRect(getLowX(patch->rect), getLowY(patch->rect), getLowZ(patch->rect), getHighX(patch->rect), getHighY(patch->rect), + getLowZ(patch->rect), "Patch " + std::to_string(patch_count), label); + ++patch_count; + } else if (content->is_wire()) { + auto* wire = static_cast(content); + // Add wire (default red). + auto label = component_mode ? "Component " + std::to_string(component[v]) : "Wire"; + widget->addWire(getX(wire->start), getY(wire->start), getZ(wire->start), getX(wire->end), getY(wire->end), getZ(wire->end), + "Wire " + std::to_string(wire_count), label); + ++wire_count; + } else if (content->is_via()) { + auto* via = static_cast(content); + // Add the via cut path (default blue). + auto via_label = component_mode ? "Component " + std::to_string(component[v]) : "Via Cut Path"; + widget->addVia(getStartX(via->cut_path), getStartY(via->cut_path), getStartZ(via->cut_path), getEndZ(via->cut_path), + "Via " + std::to_string(via_count) + " Cut Path", via_label); + // Add bottom shapes as rectangles (gray). + auto via_bottom_label = component_mode ? "Component " + std::to_string(component[v]) : "Via Bottom"; + for (auto& bottom_shape : via->bottom_shapes) { + widget->addRect(getLowX(bottom_shape), getLowY(bottom_shape), getLowZ(bottom_shape), getHighX(bottom_shape), getHighY(bottom_shape), + getLowZ(bottom_shape), "Via " + std::to_string(via_count) + " Bottom", via_bottom_label); + } + // Add top shapes as rectangles (gray). + auto via_top_label = component_mode ? "Component " + std::to_string(component[v]) : "Via Top"; + for (auto& top_shape : via->top_shapes) { + widget->addRect(getLowX(top_shape), getLowY(top_shape), getLowZ(top_shape), getHighX(top_shape), getHighY(top_shape), + getLowZ(top_shape), "Via " + std::to_string(via_count) + " Top", via_top_label); + } + ++via_count; + } else if (content->is_pin()) { + auto* pin = static_cast(content); + // Add each pin shape as a rectangle (yellow). + auto pin_label = component_mode ? "Component " + std::to_string(component[v]) : "Pin Shape"; + for (auto& pin_shape : pin->pin_shapes) { + widget->addRect(getLowX(pin_shape), getLowY(pin_shape), getLowZ(pin_shape), getHighX(pin_shape), getHighY(pin_shape), + getLowZ(pin_shape), "Pin " + std::to_string(pin_count) + " Shape", pin_label); + } + // Add each via cut as a vertical wire (yellow). + auto via_cut_label = component_mode ? "Component " + std::to_string(component[v]) : "Pin Via Cut"; + for (auto& via_cut : pin->via_cuts) { + auto center = getCenter(via_cut); + widget->addVia(getX(center), getY(center), getLowZ(via_cut), getHighZ(via_cut), "Pin " + std::to_string(pin_count) + " Via Cut", + via_cut_label); + } + ++pin_count; + } + } + // Setup the view. + widget->autoScale(); + widget->initView(); + widget->showAxes(); + widget->resize(1600, 1200); + widget->show(); + + app.exec(); +#endif +} +void VecNetGraphGenerator::toQt(const WireGraph& graph) const +{ +#ifdef BUILD_VEC_GUI + // Create the Qt application if needed (assumes one is not already running) + int argc = 0; + char** argv = nullptr; + auto app = QApplication(argc, argv); + + // Create the widget. + VecGraphWidget* widget = new VecGraphWidget(); + + // Compute connected components for color selection if needed. + std::vector component(boost::num_vertices(graph)); + + size_t wire_idx = 0; + size_t via_idx = 0; + + auto [e_iter, e_end] = boost::edges(graph); + for (; e_iter != e_end; ++e_iter) { + auto e = *e_iter; + auto u = boost::source(e, graph); + auto v = boost::target(e, graph); + size_t path_idx = 0; + // plot line + for (const auto& [start, end] : graph[e].path) { + auto label = "Component " + std::to_string(component[u]); + auto start_z = getZ(start); + auto end_z = getZ(end); + if (start_z != end_z) { + widget->addVia(getX(start), getY(start), start_z, end_z, "Via " + std::to_string(via_idx), label); + } else { + widget->addWire(getX(start), getY(start), getZ(start), getX(end), getY(end), getZ(end), "Wire " + std::to_string(wire_idx), label); + } + ++path_idx; + } + if (graph[u].layer_id == graph[v].layer_id) { + wire_idx++; + } else { + via_idx++; + } + } + + // Setup the view. + widget->autoScale(); + widget->initView(); + widget->showAxes(); + widget->resize(1600, 1200); + widget->show(); + + app.exec(); +#endif +} +void VecNetGraphGenerator::toJs(const std::vector& graphs, const std::string& path) const +{ + std::ofstream file(path); + file << "{\n"; + file << " \"shapes\": [\n"; + + bool first_shape = true; + + for (size_t graph_idx = 0; graph_idx < graphs.size(); ++graph_idx) { + const auto& graph = graphs[graph_idx]; + + // Calculate connected components for this graph to determine colors + std::vector component(boost::num_vertices(graph)); + auto num_components = boost::connected_components(graph, component.data()); + + // Counters for naming shapes within this graph + size_t patch_count = 0; + size_t wire_count = 0; + size_t via_count = 0; + size_t pin_count = 0; + + auto [v_iter, v_end] = boost::vertices(graph); + for (; v_iter != v_end; ++v_iter) { + auto v = *v_iter; + auto* content = graph[v].content; + + if (content->is_patch()) { + auto* patch = static_cast(content); + + if (!first_shape) + file << ",\n"; + first_shape = false; + + file << " {\n"; + file << " \"type\": \"Rect\",\n"; + file << " \"x1\": " << getLowX(patch->rect) << ",\n"; + file << " \"y1\": " << getLowY(patch->rect) << ",\n"; + file << " \"z1\": " << getLowZ(patch->rect) << ",\n"; + file << " \"x2\": " << getHighX(patch->rect) << ",\n"; + file << " \"y2\": " << getHighY(patch->rect) << ",\n"; + file << " \"z2\": " << getLowZ(patch->rect) << ",\n"; + file << " \"comment\": \"Graph " << graph_idx << " Patch " << patch_count << "\",\n"; + file << " \"shapeClass\": \"Graph" << graph_idx << "_Patches\",\n"; + file << " \"color\": { \"r\": 0, \"g\": 0.5, \"b\": 0 }\n"; + file << " }"; + + patch_count++; + + } else if (content->is_wire()) { + auto* wire = static_cast(content); + + if (!first_shape) + file << ",\n"; + first_shape = false; + + // Generate color based on component ID (use tab10 colormap approximation) + double hue = (component[v] % 10) / 10.0; + double r = 0.5 + 0.5 * std::sin(hue * 6.28); + double g = 0.5 + 0.5 * std::sin((hue + 0.33) * 6.28); + double b = 0.5 + 0.5 * std::sin((hue + 0.66) * 6.28); + + file << " {\n"; + file << " \"type\": \"Wire\",\n"; + file << " \"x1\": " << getX(wire->start) << ",\n"; + file << " \"y1\": " << getY(wire->start) << ",\n"; + file << " \"z1\": " << getZ(wire->start) << ",\n"; + file << " \"x2\": " << getX(wire->end) << ",\n"; + file << " \"y2\": " << getY(wire->end) << ",\n"; + file << " \"z2\": " << getZ(wire->end) << ",\n"; + file << " \"comment\": \"Graph " << graph_idx << " Wire " << wire_count << " Component " << component[v] << "\",\n"; + if (graph_idx == 102) { + file << " \"shapeClass\": \"Graph " << graph_idx << " Wire " << wire_count << " Component " << component[v] << "\",\n"; + } else { + file << " \"shapeClass\": \"Graph" << graph_idx << "_Wires_Comp" << component[v] << "\",\n"; + } + // file << " \"shapeClass\": \"Graph" << graph_idx << "_Wires_Comp" << component[v] << "\",\n"; + file << " \"color\": { \"r\": " << r << ", \"g\": " << g << ", \"b\": " << b << " }\n"; + file << " }"; + + wire_count++; + + } else if (content->is_via()) { + auto* via = static_cast(content); + + // Generate color based on component ID + double hue = (component[v] % 10) / 10.0; + double r = 0.5 + 0.5 * std::sin(hue * 6.28); + double g = 0.5 + 0.5 * std::sin((hue + 0.33) * 6.28); + double b = 0.5 + 0.5 * std::sin((hue + 0.66) * 6.28); + + // Add cut path as a via + if (!first_shape) + file << ",\n"; + first_shape = false; + + file << " {\n"; + file << " \"type\": \"Via\",\n"; + file << " \"x1\": " << getStartX(via->cut_path) << ",\n"; + file << " \"y1\": " << getStartY(via->cut_path) << ",\n"; + file << " \"z1\": " << getStartZ(via->cut_path) << ",\n"; + file << " \"x2\": " << getEndX(via->cut_path) << ",\n"; + file << " \"y2\": " << getEndY(via->cut_path) << ",\n"; + file << " \"z2\": " << getEndZ(via->cut_path) << ",\n"; + file << " \"comment\": \"Graph " << graph_idx << " Via " << via_count << " Cut Path\",\n"; + if (graph_idx == 102) { + file << " \"shapeClass\": \"Graph " << graph_idx << " Via " << via_count << " Cut Path Component " << component[v] + << "\",\n"; + } else { + file << " \"shapeClass\": \"Graph" << graph_idx << "_Vias_Comp" << component[v] << "\",\n"; + } + // file << " \"shapeClass\": \"Graph" << graph_idx << "_Vias_Comp" << component[v] << "\",\n"; + file << " \"color\": { \"r\": " << r << ", \"g\": " << g << ", \"b\": " << b << " }\n"; + file << " }"; + + // Add bottom shapes as rectangles + size_t bottom_count = 0; + for (auto& bottom_shape : via->bottom_shapes) { + if (!first_shape) + file << ",\n"; + first_shape = false; + + file << " {\n"; + file << " \"type\": \"Rect\",\n"; + file << " \"x1\": " << getLowX(bottom_shape) << ",\n"; + file << " \"y1\": " << getLowY(bottom_shape) << ",\n"; + file << " \"z1\": " << getLowZ(bottom_shape) << ",\n"; + file << " \"x2\": " << getHighX(bottom_shape) << ",\n"; + file << " \"y2\": " << getHighY(bottom_shape) << ",\n"; + file << " \"z2\": " << getLowZ(bottom_shape) << ",\n"; + file << " \"comment\": \"Graph " << graph_idx << " Via " << via_count << " Bottom " << bottom_count << "\",\n"; + if (graph_idx == 102) { + file << " \"shapeClass\": \"Graph " << graph_idx << " Via " << via_count << " Bottoms Component " << component[v] + << "\",\n"; + } else { + file << " \"shapeClass\": \"Graph" << graph_idx << "_ViaBottoms\",\n"; + } + // file << " \"shapeClass\": \"Graph" << graph_idx << "_ViaBottoms\",\n"; + file << " \"color\": { \"r\": 0.5, \"g\": 0.5, \"b\": 0.5 }\n"; + file << " }"; + bottom_count++; + } + + // Add top shapes as rectangles + size_t top_count = 0; + for (auto& top_shape : via->top_shapes) { + if (!first_shape) + file << ",\n"; + first_shape = false; + + file << " {\n"; + file << " \"type\": \"Rect\",\n"; + file << " \"x1\": " << getLowX(top_shape) << ",\n"; + file << " \"y1\": " << getLowY(top_shape) << ",\n"; + file << " \"z1\": " << getLowZ(top_shape) << ",\n"; + file << " \"x2\": " << getHighX(top_shape) << ",\n"; + file << " \"y2\": " << getHighY(top_shape) << ",\n"; + file << " \"z2\": " << getLowZ(top_shape) << ",\n"; + file << " \"comment\": \"Graph " << graph_idx << " Via " << via_count << " Top " << top_count << "\",\n"; + if (graph_idx == 102) { + file << " \"shapeClass\": \"Graph " << graph_idx << " Via " << via_count << " Tops Component " << component[v] << "\",\n"; + } else { + file << " \"shapeClass\": \"Graph" << graph_idx << "_ViaTops\",\n"; + } + // file << " \"shapeClass\": \"Graph" << graph_idx << "_ViaTops\",\n"; + file << " \"color\": { \"r\": 0.5, \"g\": 0.5, \"b\": 0.5 }\n"; + file << " }"; + top_count++; + } + + via_count++; + + } else if (content->is_pin()) { + auto* pin = static_cast(content); + auto pin_name = pin->net_name + "/" + pin->pin_name; + + // Pin color: red for driver pins, yellow for non-driver pins + double r = pin->is_driver_pin ? 1.0 : 1.0; + double g = pin->is_driver_pin ? 0.0 : 1.0; + double b = 0.0; + std::string pin_class = pin->is_driver_pin ? "DriverPins" : "ReceiverPins"; + + // Add pin shapes as rectangles + size_t pin_shape_count = 0; + for (auto& pin_shape : pin->pin_shapes) { + if (!first_shape) + file << ",\n"; + first_shape = false; + + file << " {\n"; + file << " \"type\": \"Rect\",\n"; + file << " \"x1\": " << getLowX(pin_shape) << ",\n"; + file << " \"y1\": " << getLowY(pin_shape) << ",\n"; + file << " \"z1\": " << getLowZ(pin_shape) << ",\n"; + file << " \"x2\": " << getHighX(pin_shape) << ",\n"; + file << " \"y2\": " << getHighY(pin_shape) << ",\n"; + file << " \"z2\": " << getLowZ(pin_shape) << ",\n"; + file << " \"comment\": \"Graph " << graph_idx << " Pin " << pin_name << " Shape " << pin_shape_count << "\",\n"; + file << " \"shapeClass\": \"Graph" << graph_idx << "_" << pin_class << "\",\n"; + file << " \"color\": { \"r\": " << r << ", \"g\": " << g << ", \"b\": " << b << " }\n"; + file << " }"; + pin_shape_count++; + } + + // Add via cuts as vias + size_t via_cut_count = 0; + for (auto& via_cut : pin->via_cuts) { + auto center = getCenter(via_cut); + + if (!first_shape) + file << ",\n"; + first_shape = false; + + file << " {\n"; + file << " \"type\": \"Via\",\n"; + file << " \"x1\": " << getX(center) << ",\n"; + file << " \"y1\": " << getY(center) << ",\n"; + file << " \"z1\": " << getLowZ(via_cut) << ",\n"; + file << " \"x2\": " << getX(center) << ",\n"; + file << " \"y2\": " << getY(center) << ",\n"; + file << " \"z2\": " << getHighZ(via_cut) << ",\n"; + file << " \"comment\": \"Graph " << graph_idx << " Pin " << pin_name << " Via Cut " << via_cut_count << "\",\n"; + file << " \"shapeClass\": \"Graph" << graph_idx << "_" << pin_class << "_Vias\",\n"; + file << " \"color\": { \"r\": " << r << ", \"g\": " << g << ", \"b\": " << b << " }\n"; + file << " }"; + via_cut_count++; + } + + pin_count++; + } + } + } + + file << "\n ]\n"; + file << "}\n"; +} +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/graph/data_manager/vec_net_graph_gen.hh b/src/vectorization/src/graph/data_manager/vec_net_graph_gen.hh new file mode 100644 index 0000000000000000000000000000000000000000..47dc683ae12b98a3f313374f6e08a2d5b60bc992 --- /dev/null +++ b/src/vectorization/src/graph/data_manager/vec_net_graph_gen.hh @@ -0,0 +1,362 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file vec_net_graph_gen.hh + * @author Dawn Li (dawnli619215645@gmail.com) + * @version 1.0 + * @date 2024-11-29 + * @brief Construct graph from net data. + * Remark: + * Wire, start from a point to another point (Vertex) + * Via, a via from one layer to another layer, include top/bottom rects (Edge) + * Patch, a rectangle area in a layer (Edge) + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "IdbGeometry.h" +#include "IdbNet.h" + +namespace ivec { + +// Alias for simplicity +namespace bg = boost::geometry; +namespace bgi = boost::geometry::index; + +using LayoutDefPoint = bg::model::point; +using LayoutDefSeg = bg::model::segment; +using LayoutDefRect = bg::model::box; + +struct LayoutDefPointHash +{ + std::size_t operator()(const LayoutDefPoint& point) const + { + std::size_t seed = 0; + boost::hash_combine(seed, point.get<0>()); + boost::hash_combine(seed, point.get<1>()); + boost::hash_combine(seed, point.get<2>()); + return seed; + } +}; + +struct LayoutDefPointEqual +{ + bool operator()(const LayoutDefPoint& lhs, const LayoutDefPoint& rhs) const { return boost::geometry::equals(lhs, rhs); } +}; + +struct LayoutDefSegHash +{ + std::size_t operator()(const LayoutDefSeg& seg) const + { + std::size_t seed = 0; + boost::hash_combine(seed, seg.first.get<0>()); + boost::hash_combine(seed, seg.first.get<1>()); + boost::hash_combine(seed, seg.first.get<2>()); + boost::hash_combine(seed, seg.second.get<0>()); + boost::hash_combine(seed, seg.second.get<1>()); + boost::hash_combine(seed, seg.second.get<2>()); + return seed; + } +}; + +struct LayoutDefSegEqual +{ + bool operator()(const LayoutDefSeg& lhs, const LayoutDefSeg& rhs) const { return boost::geometry::equals(lhs, rhs); } +}; + +struct LayoutDefRectHash +{ + std::size_t operator()(const LayoutDefRect& rect) const + { + std::size_t seed = 0; + boost::hash_combine(seed, rect.min_corner().get<0>()); + boost::hash_combine(seed, rect.min_corner().get<1>()); + boost::hash_combine(seed, rect.min_corner().get<2>()); + boost::hash_combine(seed, rect.max_corner().get<0>()); + boost::hash_combine(seed, rect.max_corner().get<1>()); + boost::hash_combine(seed, rect.max_corner().get<2>()); + return seed; + } +}; + +struct LayoutDefRectEqual +{ + bool operator()(const LayoutDefRect& lhs, const LayoutDefRect& rhs) const { return boost::geometry::equals(lhs, rhs); } +}; + +enum LayoutPropertyType +{ + kNone, + kWire, + kVia, + kPatch, + kPin +}; + +struct LayoutBase +{ + public: + LayoutBase(const LayoutPropertyType& t) : type(t) {} + virtual ~LayoutBase() {} + bool is_wire() const { return type == kWire; } + bool is_via() const { return type == kVia; } + bool is_patch() const { return type == kPatch; } + bool is_pin() const { return type == kPin; } + LayoutPropertyType type = kNone; +}; + +struct LayoutWire : public LayoutBase +{ + public: + LayoutWire(idb::IdbCoordinate* s, idb::IdbCoordinate* e, int layer_id) : LayoutBase{LayoutPropertyType::kWire} + { + start = LayoutDefPoint(s->get_x(), s->get_y(), layer_id); + end = LayoutDefPoint(e->get_x(), e->get_y(), layer_id); + } + LayoutDefPoint start; + LayoutDefPoint end; +}; + +struct LayoutVia : public LayoutBase +{ + public: + LayoutVia(idb::IdbCoordinate* coord, std::vector b_shapes, std::vector t_shapes, int layer_id) + : LayoutBase{LayoutPropertyType::kVia} + { + LayoutDefPoint cut_start(coord->get_x(), coord->get_y(), layer_id - 1); + LayoutDefPoint cut_end(coord->get_x(), coord->get_y(), layer_id + 1); + cut_path = LayoutDefSeg(cut_start, cut_end); + for (auto* rect : b_shapes) { + LayoutDefPoint low(rect->get_low_x(), rect->get_low_y(), layer_id - 1); + LayoutDefPoint high(rect->get_high_x(), rect->get_high_y(), layer_id - 1); + bottom_shapes.push_back(LayoutDefRect(low, high)); + } + for (auto* rect : t_shapes) { + LayoutDefPoint low(rect->get_low_x(), rect->get_low_y(), layer_id + 1); + LayoutDefPoint high(rect->get_high_x(), rect->get_high_y(), layer_id + 1); + top_shapes.push_back(LayoutDefRect(low, high)); + } + } + LayoutDefSeg cut_path; + std::vector bottom_shapes; + std::vector top_shapes; +}; + +struct LayoutPatch : public LayoutBase +{ + public: + LayoutPatch(idb::IdbRect* r, int layer_id) : LayoutBase{LayoutPropertyType::kPatch} + { + LayoutDefPoint low(r->get_low_x(), r->get_low_y(), layer_id); + LayoutDefPoint high(r->get_high_x(), r->get_high_y(), layer_id); + rect = LayoutDefRect(low, high); + } + LayoutDefRect rect; +}; + +struct LayoutPin : public LayoutBase +{ + public: + LayoutPin() : LayoutBase{LayoutPropertyType::kPin} {} + LayoutPin(const std::string& net_name, const std::string& pin_name, const bool is_driver_pin) + : LayoutBase{LayoutPropertyType::kPin}, net_name(net_name), pin_name(pin_name), is_driver_pin(is_driver_pin) + { + } + void addPinShape(idb::IdbRect* r, int layer_id) + { + LayoutDefPoint low(r->get_low_x(), r->get_low_y(), layer_id); + LayoutDefPoint high(r->get_high_x(), r->get_high_y(), layer_id); + pin_shapes.push_back(LayoutDefRect(low, high)); + } + void addViaCut(idb::IdbRect* r, int layer_id) + { + LayoutDefPoint low(r->get_low_x(), r->get_low_y(), layer_id - 1); + LayoutDefPoint high(r->get_high_x(), r->get_high_y(), layer_id + 1); + via_cuts.push_back(LayoutDefRect(low, high)); + } + std::string net_name = ""; + std::string pin_name = ""; + bool is_driver_pin = false; + std::vector pin_shapes; + std::vector via_cuts; +}; + +// R-tree value type +using RTreeVal = std::pair; +// Main class to store shapes and perform intersection searches +class LayoutShapeManager +{ + public: + LayoutShapeManager() {} + ~LayoutShapeManager() {} + + void addShape(const LayoutDefPoint& point, const size_t& vertex_id) { addShape(LayoutDefRect(point, point), vertex_id); } + void addShape(const LayoutDefSeg& seg, const size_t& vertex_id) { addShape(LayoutDefRect(seg.first, seg.second), vertex_id); } + void addShape(const LayoutDefRect& box, const size_t& vertex_id) { _rtree.insert(std::make_pair(box, vertex_id)); } + + std::vector findIntersections(const LayoutDefRect& box) const + { + std::vector result; + _rtree.query(bgi::intersects(box), std::back_inserter(result)); + std::unordered_set vertex_ids; + for (const auto& [rect, vertex_id] : result) { + vertex_ids.insert(vertex_id); + } + return std::vector(vertex_ids.begin(), vertex_ids.end()); + } + + std::vector findIntersections(const LayoutDefPoint& point) const + { + LayoutDefRect box(point, point); + return findIntersections(box); + } + + std::vector findIntersections(const LayoutDefPoint& start, const LayoutDefPoint& end) const + { + LayoutDefRect box(start, end); + return findIntersections(box); + } + + std::vector findIntersections(const LayoutDefSeg& seg) const + { + LayoutDefRect box(seg.first, seg.second); + return findIntersections(box); + } + + void clear() { _rtree.clear(); } + + private: + bgi::rtree> _rtree; // Spatial index +}; + +struct TopoGraphVertexProperty +{ + LayoutBase* content; +}; + +using TopoGraph = boost::adjacency_list; +using TopoGraphVertex = boost::graph_traits::vertex_descriptor; +using TopoGraphEdge = boost::graph_traits::edge_descriptor; + +struct WireGraphVertexProperty +{ + int x; + int y; + int layer_id; + bool is_pin = false; + bool is_driver_pin = false; +}; + +struct WireGraphEdgeProperty +{ + std::vector> path; +}; + +using WireGraph = boost::adjacency_list; +using WireGraphVertex = boost::graph_traits::vertex_descriptor; +using WireGraphEdge = boost::graph_traits::edge_descriptor; +using WireGraphVertexMap = std::unordered_map; + +class VecNetGraphGenerator +{ + public: + VecNetGraphGenerator() { initLayerMap(); }; + ~VecNetGraphGenerator() {} + + void initLayerMap(); + WireGraph buildGraph(idb::IdbNet* idb_net) const; + std::vector buildGraphs() const; + bool isCornerCase(idb::IdbNet* idb_net) const; + WireGraph buildCornerCaseGraph(idb::IdbNet* idb_net) const; + + // Topo Graph + TopoGraph buildTopoGraph(idb::IdbNet* idb_net) const; + TopoGraph buildTopoGraph(idb::IdbSpecialNet* idb_net) const; + LayoutShapeManager buildShapeManager(const TopoGraph& graph) const; + void buildConnections(TopoGraph& graph) const; + bool checkConnectivity(const TopoGraph& graph) const; + + // Wire Graph + WireGraph buildWireGraph(const TopoGraph& graph) const; + std::vector canonicalizeCycle(const std::vector& cycle) const; + void dfsFindCycles(const WireGraph& graph, WireGraphVertex start, WireGraphVertex current, std::vector& visited, + std::vector& path, std::vector>& cycles) const; + + std::vector> findAllCycles(const WireGraph& graph) const; + void breakCycle(WireGraph& graph) const; + void innerConnectivityCompletion(const TopoGraph& graph, WireGraph& wire_graph, WireGraphVertexMap& point_to_vertex) const; + void buildVirtualWire(const TopoGraph& graph, WireGraph& wire_graph, WireGraphVertexMap& point_to_vertex) const; + void markPinVertex(const TopoGraph& graph, WireGraph& wire_graph) const; + void reduceWireGraph(WireGraph& graph, const bool& retain_pin = true) const; + bool hasCycleUtil(const WireGraph& graph, WireGraphVertex v, std::vector& visited, WireGraphVertex parent) const; + bool hasCycle(const WireGraph& graph) const; + bool checkConnectivity(const WireGraph& graph) const; + bool checkDriverIsTreeRoot(const TopoGraph& topo_graph, const WireGraph& wire_graph) const; + std::vector> generateShortestPath(const std::vector& points, + const std::vector& regions) const; + std::vector> findByDijkstra(const std::vector& points, + const std::vector& path_points, + const std::vector& regions) const; + std::vector generateCrossroadsPoints(const LayoutDefPoint& p, const LayoutDefRect& rect) const; + LayoutDefPoint generatePointPivot(const LayoutDefPoint& p, const LayoutDefRect& rect) const; + LayoutDefPoint generateSegPivot(const LayoutDefSeg& seg, const LayoutDefRect& rect) const; + + // debug + void toPy(const TopoGraph& graph, const std::string& path) const; + void toPy(const WireGraph& graph, const std::string& path) const; + void toJs(const std::vector& graphs, const std::string& path) const; + void toQt(const TopoGraph& graph, const bool& component_mode = false) const; + void toQt(const WireGraph& graph) const; + + static int getX(const LayoutDefPoint& point) { return bg::get<0>(point); } + static int getY(const LayoutDefPoint& point) { return bg::get<1>(point); } + static int getZ(const LayoutDefPoint& point) { return bg::get<2>(point); } + static int getStartX(const LayoutDefSeg& seg) { return bg::get<0, 0>(seg); } + static int getStartY(const LayoutDefSeg& seg) { return bg::get<0, 1>(seg); } + static int getStartZ(const LayoutDefSeg& seg) { return bg::get<0, 2>(seg); } + static int getEndX(const LayoutDefSeg& seg) { return bg::get<1, 0>(seg); } + static int getEndY(const LayoutDefSeg& seg) { return bg::get<1, 1>(seg); } + static int getEndZ(const LayoutDefSeg& seg) { return bg::get<1, 2>(seg); } + static int getLowX(const LayoutDefRect& rect) { return bg::get(rect); } + static int getLowY(const LayoutDefRect& rect) { return bg::get(rect); } + static int getLowZ(const LayoutDefRect& rect) { return bg::get(rect); } + static int getHighX(const LayoutDefRect& rect) { return bg::get(rect); } + static int getHighY(const LayoutDefRect& rect) { return bg::get(rect); } + static int getHighZ(const LayoutDefRect& rect) { return bg::get(rect); } + static int getWidth(const LayoutDefRect& rect) { return getHighX(rect) - getLowX(rect); } + static int getHeight(const LayoutDefRect& rect) { return getHighY(rect) - getLowY(rect); } + static LayoutDefPoint getCenter(const LayoutDefSeg& seg) + { + return LayoutDefPoint((getStartX(seg) + getEndX(seg)) / 2, (getStartY(seg) + getEndY(seg)) / 2, (getStartZ(seg) + getEndZ(seg)) / 2); + } + static LayoutDefPoint getCenter(const LayoutDefRect& rect) + { + return LayoutDefPoint((getLowX(rect) + getHighX(rect)) / 2, (getLowY(rect) + getHighY(rect)) / 2, (getLowZ(rect) + getHighZ(rect)) / 2); + } + + private: + std::unordered_map _layer_map; +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/layout/CMakeLists.txt b/src/vectorization/src/layout/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..0140a16517d0248e5635b4f38621ce3a0389d752 --- /dev/null +++ b/src/vectorization/src/layout/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(database) +add_subdirectory(data_manager) diff --git a/src/vectorization/src/layout/data_manager/CMakeLists.txt b/src/vectorization/src/layout/data_manager/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..931fc07f3f9e9b9dbdd03a8ff6db267f35ccf7dd --- /dev/null +++ b/src/vectorization/src/layout/data_manager/CMakeLists.txt @@ -0,0 +1,28 @@ +add_library(ivec_layout_dm + vec_layout_dm.cpp + vec_layout_init.cpp + vec_wire_pattern.cc + vec_pattern_gen.cc +) + +# find_package(OpenCV REQUIRED) + +target_link_libraries(ivec_layout_dm + PUBLIC + idb + idm + geometry_db + log + usage + ivec_db + ivec_layout_db + ivec_util +) + +target_include_directories(ivec_layout_dm + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${HOME_UTILITY}/json +) + +include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) \ No newline at end of file diff --git a/src/operation/iPNP/api/iPNPApi.cpp b/src/vectorization/src/layout/data_manager/vec_layout_dm.cpp similarity index 71% rename from src/operation/iPNP/api/iPNPApi.cpp rename to src/vectorization/src/layout/data_manager/vec_layout_dm.cpp index 477160fe0a90df941949f82118c57d2b5ee759e7..319aebf3e8b26061fcac65e57487586c4172e21e 100644 --- a/src/operation/iPNP/api/iPNPApi.cpp +++ b/src/vectorization/src/layout/data_manager/vec_layout_dm.cpp @@ -14,28 +14,25 @@ // // See the Mulan PSL v2 for more details. // *************************************************************************************** -/** - * @file iPNPApi.hh - * @author Jianrong Su - * @brief - * @version 1.0 - * @date 2025-06-23 - */ -#include "iPNPApi.hh" +#include "Log.hh" +#include "omp.h" +#include "usage.hh" +#include "vec_layout_dm.h" +#include "vec_layout_init.h" -#include "iPNP.hh" +namespace ivec { +bool VecLayoutDataManager::buildLayoutData() +{ + init(); -namespace ipnp { - -iPNP* iPNPApi::_ipnp_instance = nullptr; - -void iPNPApi::setInstance(iPNP* ipnp) { - _ipnp_instance = ipnp; + return true; } -iPNP* iPNPApi::getInstance() { - return _ipnp_instance; +void VecLayoutDataManager::init() +{ + VecLayoutInit layout_init(&_layout); + layout_init.init(); } -} // namespace ipnp \ No newline at end of file +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/layout/data_manager/vec_layout_dm.h b/src/vectorization/src/layout/data_manager/vec_layout_dm.h new file mode 100644 index 0000000000000000000000000000000000000000..07be3d03b40298a8a9f4624f7864bf2f3c4e7362 --- /dev/null +++ b/src/vectorization/src/layout/data_manager/vec_layout_dm.h @@ -0,0 +1,42 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "vec_layout.h" +#include "vec_net.h" + +namespace ivec { + +class VecLayoutDataManager +{ + public: + VecLayoutDataManager() {} + ~VecLayoutDataManager() {} + + VecLayout& get_layout() { return _layout; } + std::map& get_graph() { return _layout.get_graph().get_net_map(); } + + bool buildLayoutData(); + + private: + VecLayout _layout; + + void init(); +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/layout/data_manager/vec_layout_init.cpp b/src/vectorization/src/layout/data_manager/vec_layout_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91788860af2a5a180d28eeeebb78f054180247db --- /dev/null +++ b/src/vectorization/src/layout/data_manager/vec_layout_init.cpp @@ -0,0 +1,847 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** + +#include "vec_layout_init.h" + +#include "IdbGeometry.h" +#include "IdbLayer.h" +#include "IdbLayerShape.h" +#include "IdbNet.h" +#include "IdbRegularWire.h" +#include "IdbSpecialNet.h" +#include "IdbSpecialWire.h" +#include "Log.hh" +#include "idm.h" +#include "omp.h" +#include "usage.hh" +#include "vec_cell.h" +#include "vec_grid_info.h" +#include "vec_instance.h" + +namespace ivec { + +void VecLayoutInit::init() +{ + initViaIds(); + + initCells(); + initLayers(); + initDie(); + initTracks(); + // initPDN(); + initInstances(); + // initIOPins(); + + initNets(); +} + +void VecLayoutInit::initViaIds() +{ + auto* idb_layout = dmInst->get_idb_layout(); + auto* idb_design = dmInst->get_idb_design(); + auto* idb_lef_vias = idb_layout->get_via_list(); + auto* idb_def_vias = idb_design->get_via_list(); + + int index = 0; + for (auto* via : idb_lef_vias->get_via_list()) { + _layout->add_via_map(index++, via->get_name()); + } + + for (auto* via : idb_def_vias->get_via_list()) { + _layout->add_via_map(index++, via->get_name()); + } + + LOG_INFO << "Via number : " << index; +} + +void VecLayoutInit::initDie() +{ + auto* idb_layout = dmInst->get_idb_layout(); + auto* idb_die = idb_layout->get_die(); + + auto& layout_layers = _layout->get_layout_layers(); + for (auto& [order, layout_layer] : layout_layers.get_layout_layer_map()) { + layout_layer.set_llx(idb_die->get_llx()); + layout_layer.set_lly(idb_die->get_lly()); + layout_layer.set_urx(idb_die->get_urx()); + layout_layer.set_ury(idb_die->get_ury()); + + gridInfoInst.llx = idb_die->get_llx(); + gridInfoInst.lly = idb_die->get_lly(); + gridInfoInst.urx = idb_die->get_urx(); + gridInfoInst.ury = idb_die->get_ury(); + } +} + +void VecLayoutInit::initLayers() +{ + auto* idb_layout = dmInst->get_idb_layout(); + auto* idb_layers = idb_layout->get_layers(); + auto idb_layer_1st = dmInst->get_config().get_routing_layer_1st(); + + auto& layout_layers = _layout->get_layout_layers(); + auto& layout_layer_map = layout_layers.get_layout_layer_map(); + + bool b_record = false; + int index = 0; + for (auto* idb_layer : idb_layers->get_layers()) { + if (idb_layer->get_name() == idb_layer_1st) { + b_record = true; + } + + if (true == b_record) { + _layout->add_layer_map(index, idb_layer->get_name()); + + VecLayoutLayer layout_layer; + layout_layer.set_layer_name(idb_layer->get_name()); + layout_layer.set_layer_order(index); + layout_layer.set_as_routing(idb_layer->is_routing()); + if (idb_layer->is_routing()) { + auto* routing_layer = dynamic_cast(idb_layer); + layout_layer.set_horizontal(routing_layer->is_horizontal()); + layout_layer.set_wire_width(routing_layer->get_width()); + } + + auto& grid = layout_layer.get_grid(); + grid.layer_order = index; + + // layout_layer_map.insert(std::make_pair(index, layout_layer)); + layout_layer_map.emplace(index, std::move(layout_layer)); + + index++; + + if (false == idb_layer->is_cut() && false == idb_layer->is_routing()) { + break; + } + } + } + + layout_layers.set_layer_order_bottom(0); + layout_layers.set_layer_order_top(index - 1); + + LOG_INFO << "Layer number : " << index; +} + +void VecLayoutInit::initCells() +{ + auto idb2Vec = [](int i, idb::IdbCellMaster* idb_cell) -> VecCell { + VecCell vec_cell; + vec_cell.id = i; + vec_cell.name = idb_cell->get_name(); + vec_cell.width = idb_cell->get_width(); + vec_cell.height = idb_cell->get_height(); + + return vec_cell; + }; + + ieda::Stats stats; + + LOG_INFO << "Vectorization init cells start..."; + + /// find base track + auto* idb_layout = dmInst->get_idb_layout(); + auto* idb_cell_masters = idb_layout->get_cell_master_list(); + for (int i = 0; i < idb_cell_masters->get_cell_master_num(); ++i) { + auto* idb_cell = idb_cell_masters->get_cell_master()[i]; + VecCell vec_cell = idb2Vec(i, idb_cell); + _layout->add_cell(vec_cell); + } + + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + + LOG_INFO << "Vectorization init cells end..."; +} + +void VecLayoutInit::initTrackGrid(idb::IdbTrackGrid* idb_track_grid) +{ + auto start = idb_track_grid->get_track()->get_start(); + auto pitch = idb_track_grid->get_track()->get_pitch(); + + if (idb_track_grid->get_track()->is_track_vertical()) { + gridInfoInst.x_start = start; + gridInfoInst.x_step = pitch / 2; + } else { + gridInfoInst.y_start = start; + gridInfoInst.y_step = pitch / 2; + } +} + +void VecLayoutInit::initTracks() +{ + ieda::Stats stats; + + LOG_INFO << "Vectorization init tracks start..."; + + /// find base track + auto* idb_layout = dmInst->get_idb_layout(); + auto* idb_layers = idb_layout->get_layers(); + + auto& routing_layer_list = idb_layers->get_routing_layers(); + + idb::IdbLayerRouting* idb_layer = nullptr; + if (routing_layer_list.size() >= 2) { + /// use 2nd routing layer pitch to divide grid + idb_layer = dynamic_cast(routing_layer_list[1]); + } else { + /// use bottom routing layer pitch to divide grid + idb_layer = dynamic_cast(routing_layer_list[0]); + } + + LOG_INFO << "Vectorization init tracks by routing layer " << idb_layer->get_name(); + + auto* idb_track_grid_prefer = idb_layer->get_prefer_track_grid(); + auto* idb_track_grid_nonprefer = idb_layer->get_nonprefer_track_grid(); + + auto& layout_layers = _layout->get_layout_layers(); + auto& layout_layer_map = layout_layers.get_layout_layer_map(); + + initTrackGrid(idb_track_grid_prefer); + initTrackGrid(idb_track_grid_nonprefer); + + buildLayoutGrid(); + + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + + LOG_INFO << "Vectorization init tracks end..."; +} + +void VecLayoutInit::buildLayoutGrid() +{ + auto& layout_layers = _layout->get_layout_layers(); + auto& layout_layer_map = layout_layers.get_layout_layer_map(); + // #pragma omp parallel for schedule(dynamic) + for (int i = 0; i < (int) layout_layer_map.size(); ++i) { + // for (auto& [order, layout_layer] : layout_layer_map) { + auto it = layout_layer_map.begin(); + std::advance(it, i); + auto order = it->first; + auto& layout_layer = it->second; + + auto& grid = layout_layer.get_grid(); + auto [node_row_num, node_col_num] = grid.buildNodeMatrix(order); + + LOG_INFO << "Vectorization layer order : " << order << ", row = " << node_row_num << ", col = " << node_col_num; + } +} + +void VecLayoutInit::transVia(idb::IdbVia* idb_via, int net_id, VecNodeTYpe type) +{ + auto& layout_layers = _layout->get_layout_layers(); + + /// cut layer + auto cut_layer_shape = idb_via->get_cut_layer_shape(); + auto order = _layout->findLayerId(cut_layer_shape.get_layer()->get_name()); + auto* layout_layer = layout_layers.findLayoutLayer(order); + if (nullptr == layout_layer) { + LOG_WARNING << idb_via->get_name() << " can not get layer order : " << cut_layer_shape.get_layer()->get_name(); + return; + } + auto& grid = layout_layer->get_grid(); + auto* via_coordinate = idb_via->get_coordinate(); + auto [row, col] = gridInfoInst.findNodeID(via_coordinate->get_x(), via_coordinate->get_y()); + + auto* node = grid.get_node(row, col, true); + node->set_col_id(col); + node->set_row_id(row); + node->set_layer_id(order); + + VecNodeData* node_data = node->get_node_data(net_id, true); + node_data->set_type(type); + if (type == VecNodeTYpe::vec_net) { + node_data->set_net_id(net_id); + } + if (type == VecNodeTYpe::vec_pdn) { + node_data->set_pdn_id(net_id); + } + node_data->set_connect_type(VecNodeConnectType::vec_via); + + /// botttom + auto enclosure_bottom = idb_via->get_bottom_layer_shape(); + for (auto* rect : enclosure_bottom.get_rect_list()) { + transEnclosure(rect->get_low_x(), rect->get_low_y(), rect->get_high_x(), rect->get_high_y(), enclosure_bottom.get_layer()->get_name(), + net_id, row, col, type); + } + + /// top + auto enclosure_top = idb_via->get_top_layer_shape(); + for (auto* rect : enclosure_top.get_rect_list()) { + transEnclosure(rect->get_low_x(), rect->get_low_y(), rect->get_high_x(), rect->get_high_y(), enclosure_top.get_layer()->get_name(), + net_id, row, col, type); + } +} + +void VecLayoutInit::initPDN() +{ + ieda::Stats stats; + + LOG_INFO << "Vectorization init PDN start..."; + auto& layout_layers = _layout->get_layout_layers(); + + auto* idb_design = dmInst->get_idb_design(); + auto* idb_pdn = idb_design->get_special_net_list(); + + omp_lock_t lck; + omp_init_lock(&lck); + + int segment_total = 0; + for (auto* idb_net : idb_pdn->get_net_list()) { + auto* idb_wires = idb_net->get_wire_list(); + for (auto* idb_wire : idb_wires->get_wire_list()) { + segment_total += idb_wire->get_num(); + } + } + + int segment_num = 0; + for (int i = 0; i < idb_pdn->get_net_list().size(); ++i) { + auto* idb_net = idb_pdn->get_net_list()[i]; + /// init pdn id map + _layout->add_pdn_map(i, idb_net->get_net_name()); + + auto* idb_wires = idb_net->get_wire_list(); + for (auto* idb_wire : idb_wires->get_wire_list()) { +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < (int) idb_wire->get_segment_list().size(); ++i) { + auto* idb_segment = idb_wire->get_segment_list()[i]; + /// wire + if (idb_segment->get_point_num() >= 2) { + auto* routing_layer = dynamic_cast(idb_segment->get_layer()); + auto routing_width = idb_segment->get_route_width() == 0 ? routing_layer->get_width() : idb_segment->get_route_width(); + + /// get bounding box + int32_t ll_x = 0; + int32_t ll_y = 0; + int32_t ur_x = 0; + int32_t ur_y = 0; + + auto* point_1 = idb_segment->get_point_start(); + auto* point_2 = idb_segment->get_point_second(); + if (point_1->get_y() == point_2->get_y()) { + // horizontal + ll_x = std::min(point_1->get_x(), point_2->get_x()); + ll_y = std::min(point_1->get_y(), point_2->get_y()) - routing_width / 2; + ur_x = std::max(point_1->get_x(), point_2->get_x()); + ur_y = ll_y + routing_width; + } else if (point_1->get_x() == point_2->get_x()) { + // vertical + ll_x = std::min(point_1->get_x(), point_2->get_x()) - routing_width / 2; + ll_y = std::min(point_1->get_y(), point_2->get_y()); + ur_x = ll_x + routing_width; + ur_y = std::max(point_1->get_y(), point_2->get_y()); + } + + /// build grid + auto order = _layout->findLayerId(routing_layer->get_name()); + auto* layout_layer = layout_layers.findLayoutLayer(order); + if (nullptr == layout_layer) { + LOG_WARNING << "Can not get layer order : " << routing_layer->get_name(); + continue; + } + auto& grid = layout_layer->get_grid(); + auto [row_1, row_2, co_1, col_2] = gridInfoInst.get_node_id_range(ll_x, ur_x, ll_y, ur_y); + for (int row = row_1; row <= row_2; ++row) { + for (int col = co_1; col <= col_2; ++col) { + /// set node data + auto* node = grid.get_node(row, col, true); + VecNodeData* node_data = node->get_node_data(-1, true); + node->set_col_id(col); + node->set_row_id(row); + node->set_layer_id(order); + node_data->set_type(VecNodeTYpe::vec_pdn); + node_data->set_connect_type(VecNodeConnectType::vec_wire); + node_data->set_pdn_id(i); + } + } + } + + if (idb_segment->is_via()) { + auto* idb_via = idb_segment->get_via(); + transVia(idb_via, i, VecNodeTYpe::vec_pdn); + } + + if (i % 1000 == 0) { + omp_set_lock(&lck); + + segment_num = segment_num + 1000; + segment_num = segment_num > segment_total ? segment_total : segment_num; + + LOG_INFO << "Read segment : " << segment_num << " / " << segment_total; + + omp_unset_lock(&lck); + } + } + } + } + + omp_destroy_lock(&lck); + + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization init PDN end..."; +} + +void VecLayoutInit::initInstances() +{ + auto idb2vec = [](int inst_id, int cell_id, idb::IdbInstance* idb_inst) -> ivec::VecInstance { + ivec::VecInstance vec_inst; + + vec_inst.id = inst_id; + vec_inst.cell_id = cell_id; + vec_inst.name = idb_inst->get_name(); + + vec_inst.x = idb_inst->get_coordinate()->get_x(); + vec_inst.y = idb_inst->get_coordinate()->get_y(); + + vec_inst.width = idb_inst->get_cell_master()->get_width(); + vec_inst.height = idb_inst->get_cell_master()->get_height(); + + vec_inst.llx = idb_inst->get_bounding_box()->get_low_x(); + vec_inst.lly = idb_inst->get_bounding_box()->get_low_y(); + vec_inst.urx = idb_inst->get_bounding_box()->get_high_x(); + vec_inst.ury = idb_inst->get_bounding_box()->get_high_y(); + + vec_inst.orient = idb::IdbEnum::GetInstance()->get_site_property()->get_orient_name(idb_inst->get_orient()); + vec_inst.status = idb::IdbEnum::GetInstance()->get_instance_property()->get_status_str(idb_inst->get_status()); + + return vec_inst; + }; + + ieda::Stats stats; + + LOG_INFO << "Vectorization init instances start..."; + + auto& layout_layers = _layout->get_layout_layers(); + + auto* idb_design = dmInst->get_idb_design(); + auto* idb_insts = idb_design->get_instance_list(); + + omp_lock_t lck; + omp_init_lock(&lck); + + int inst_total = (int) idb_insts->get_instance_list().size(); + int number = 0; + + // #pragma omp parallel for schedule(dynamic) + for (int i = 0; i < inst_total; ++i) { + auto* idb_inst = idb_insts->get_instance_list()[i]; + _layout->add_instance_map(i, idb_inst->get_name()); + auto vec_inst = idb2vec(i, _layout->findCellId(idb_inst->get_cell_master()->get_name()), idb_inst); + auto cell_id = _layout->findCellId(idb_inst->get_cell_master()->get_name()); + _layout->add_instance(idb2vec(i, cell_id, idb_inst)); + + // auto* idb_inst_pins = idb_inst->get_pin_list(); + // for (auto* idb_pin : idb_inst_pins->get_pin_list()) { + // if (false == idb_pin->is_net_pin()) { + // auto type = idb_pin->is_special_net_pin() ? VecNodeTYpe::vec_pdn : VecNodeTYpe::kNone; + // transPin(idb_pin, -1, type, i); + // } + // } + + // for (auto* layer_shape : idb_inst->get_obs_box_list()) { + // auto* layer = layer_shape->get_layer(); + // auto order = _layout->findLayerId(layer->get_name()); + // auto* layout_layer = layout_layers.findLayoutLayer(order); + // if (nullptr == layout_layer) { + // // LOG_WARNING << "Can not get layer order : " << layer->get_name(); + // continue; + // } + // } + + if (i % 1000 == 0) { + omp_set_lock(&lck); + + number += 1000; + number = number > inst_total ? inst_total : number; + LOG_INFO << "Read instance : " << number << " / " << (int) inst_total; + + omp_unset_lock(&lck); + } + } + + omp_destroy_lock(&lck); + + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + + LOG_INFO << "Vectorization init instances end..."; +} + +void VecLayoutInit::initIOPins() +{ + auto* idb_design = dmInst->get_idb_design(); + auto* idb_iopins = idb_design->get_io_pin_list(); + + for (auto* io_pin : idb_iopins->get_pin_list()) { + /// net io pin has been built in init net flow + if (false == io_pin->is_net_pin()) { + auto net_id = _layout->findPdnId(io_pin->get_net_name()); + /// net has been connected + auto type = io_pin->is_special_net_pin() ? VecNodeTYpe::vec_pdn : VecNodeTYpe::kNone; + transPin(io_pin, net_id, type); + } + } +} + +void VecLayoutInit::transPin(idb::IdbPin* idb_pin, int net_id, VecNodeTYpe type, int instance_id, int pin_id, bool b_io) +{ + auto& layout_layers = _layout->get_layout_layers(); + for (auto* layer_shape : idb_pin->get_port_box_list()) { + auto order = _layout->findLayerId(layer_shape->get_layer()->get_name()); + auto* layout_layer = layout_layers.findLayoutLayer(order); + if (nullptr == layout_layer) { + /// igore pin under bottom routing layer + continue; + } + auto& grid = layout_layer->get_grid(); + + if (layer_shape->is_via()) { + for (IdbRect* rect : layer_shape->get_rect_list()) { + /// build grid + auto [row_id, col_id] = gridInfoInst.findNodeID(rect->get_middle_point_x(), rect->get_middle_point_y()); + auto* node = grid.get_node(row_id, col_id, true); + node->set_col_id(col_id); + node->set_row_id(row_id); + node->set_layer_id(order); + + VecNodeData* node_data = node->get_node_data(net_id, true); + node_data->set_type(VecNodeTYpe::vec_pin); + node_data->set_type(type); + if (type == VecNodeTYpe::vec_net) { + node_data->set_net_id(net_id); + } + + if (type == VecNodeTYpe::vec_pdn) { + node_data->set_pdn_id(net_id); + } + + if (instance_id != -1) { + node_data->set_instance_id(instance_id); + } + + if (b_io) { + node_data->set_type(VecNodeTYpe::vec_io); + } + if (node_data->get_pin_id() > -1 && pin_id != node_data->get_pin_id()) { + error_pin_num++; + } + if (pin_id > -1) { + node_data->set_pin_id(pin_id); + } + node_data->set_connect_type(VecNodeConnectType::vec_via); + } + } else { + for (IdbRect* rect : layer_shape->get_rect_list()) { + /// build grid + int llx = rect->get_low_x(); + int urx = rect->get_high_x(); + int lly = rect->get_low_y(); + int ury = rect->get_high_y(); + + auto [row_1, row_2, col_1, col_2] = gridInfoInst.get_node_id_range(llx, urx, lly, ury); + + for (int row = row_1; row <= row_2; ++row) { + for (int col = col_1; col <= col_2; ++col) { + auto* node = grid.get_node(row, col, true); + node->set_col_id(col); + node->set_row_id(row); + node->set_layer_id(order); + + VecNodeData* node_data = node->get_node_data(net_id, true); + node_data->set_type(VecNodeTYpe::vec_pin); + node_data->set_type(type); + if (type == VecNodeTYpe::vec_net) { + node_data->set_net_id(net_id); + } + + if (type == VecNodeTYpe::vec_pdn) { + node_data->set_pdn_id(net_id); + } + + if (instance_id != -1) { + node_data->set_instance_id(instance_id); + } + + if (b_io) { + node_data->set_type(VecNodeTYpe::vec_io); + } + if (node_data->get_pin_id() > -1 && pin_id != node_data->get_pin_id()) { + error_pin_num++; + } + + if (pin_id > -1) { + node_data->set_pin_id(pin_id); + } + } + } + } + } + } + + /// init via in pins + /// tbd +} + +void VecLayoutInit::transNetRect(int32_t ll_x, int32_t ll_y, int32_t ur_x, int32_t ur_y, std::string layer_name, int net_id, + VecNodeTYpe type) +{ + auto& layout_layers = _layout->get_layout_layers(); + + auto order = _layout->findLayerId(layer_name); + auto* layout_layer = layout_layers.findLayoutLayer(order); + if (nullptr == layout_layer) { + LOG_WARNING << "Can not get layer order : " << layer_name; + return; + } + + auto& grid = layout_layer->get_grid(); + auto [row_1, row_2, col_1, col_2] = gridInfoInst.get_node_id_range(ll_x, ur_x, ll_y, ur_y); + /// net wire must only occupy one grid size + for (int row = row_1; row <= row_2; ++row) { + for (int col = col_1; col <= col_2; ++col) { + /// set node data + auto* node = grid.get_node(row, col, true); + node->set_col_id(col); + node->set_row_id(row); + node->set_layer_id(order); + VecNodeData* node_data = node->get_node_data(net_id, true); + node_data->set_type(VecNodeTYpe::vec_net); + node_data->set_connect_type(VecNodeConnectType::vec_wire); + if (type == VecNodeTYpe::vec_net) { + node_data->set_net_id(net_id); + } + + if (type == VecNodeTYpe::vec_pdn) { + node_data->set_pdn_id(net_id); + } + } + } +} + +void VecLayoutInit::transEnclosure(int32_t ll_x, int32_t ll_y, int32_t ur_x, int32_t ur_y, std::string layer_name, int net_id, int via_row, + int via_col, VecNodeTYpe type) +{ + auto& layout_layers = _layout->get_layout_layers(); + + auto order = _layout->findLayerId(layer_name); + auto* layout_layer = layout_layers.findLayoutLayer(order); + if (nullptr == layout_layer) { + LOG_WARNING << "Can not get layer : " << layer_name; + return; + } + auto& grid = layout_layer->get_grid(); + auto [row_1, row_2, col_1, col_2] = gridInfoInst.get_node_id_range(ll_x, ur_x, ll_y, ur_y); + + for (int row = row_1; row <= row_2; ++row) { + for (int col = col_1; col <= col_2; ++col) { + auto* node = grid.get_node(row, col, true); + node->set_col_id(col); + node->set_row_id(row); + node->set_layer_id(order); + VecNodeData* node_data = node->get_node_data(net_id, true); + node_data->set_type(type); + node_data->set_connect_type(VecNodeConnectType::vec_enclosure); + if (type == VecNodeTYpe::vec_net) { + node_data->set_net_id(net_id); + } + + if (type == VecNodeTYpe::vec_pdn) { + node_data->set_pdn_id(net_id); + } + } + } +} + +void VecLayoutInit::transNetDelta(int32_t ll_x, int32_t ll_y, int32_t ur_x, int32_t ur_y, std::string layer_name, int net_id, + VecNodeTYpe type) +{ + auto& layout_layers = _layout->get_layout_layers(); + + auto order = _layout->findLayerId(layer_name); + auto* layout_layer = layout_layers.findLayoutLayer(order); + if (nullptr == layout_layer) { + LOG_WARNING << "Can not get layer order : " << layer_name; + return; + } + auto& grid = layout_layer->get_grid(); + auto [row_1, row_2, col_1, col_2] = gridInfoInst.get_node_id_range(ll_x, ur_x, ll_y, ur_y); + + for (int row = row_1; row <= row_2; ++row) { + for (int col = col_1; col <= col_2; ++col) { + auto* node = grid.get_node(row, col, true); + node->set_col_id(col); + node->set_row_id(row); + node->set_layer_id(order); + VecNodeData* node_data = node->get_node_data(net_id, true); + node_data->set_type(VecNodeTYpe::vec_net); + node_data->set_connect_type(VecNodeConnectType::vec_delta); + if (type == VecNodeTYpe::vec_net) { + node_data->set_net_id(net_id); + } + + if (type == VecNodeTYpe::vec_pdn) { + node_data->set_pdn_id(net_id); + } + } + } +} + +void VecLayoutInit::initNets() +{ + ieda::Stats stats; + + LOG_INFO << "Vectorization init nets start..."; + + auto* idb_design = dmInst->get_idb_design(); + auto* idb_nets = idb_design->get_net_list(); + auto& graph = _layout->get_graph(); + int pin_id = 0; + for (int net_id = 0; net_id < (int) idb_nets->get_net_list().size(); ++net_id) { + /// init net id map + auto* idb_net = idb_nets->get_net_list()[net_id]; + auto* driver_pin = idb_net->get_driving_pin(); + /// ignore net if pin number < 2 and no driver pin + if (idb_net->get_pin_number() < 2 || driver_pin == nullptr) { + continue; + } + _layout->add_net_map(net_id, idb_net->get_net_name()); + + auto* vec_net = graph.addNet(net_id); + if (vec_net == nullptr) { + continue; + } + + { + auto instance_name = driver_pin->is_io_pin() ? "" : driver_pin->get_instance()->get_name(); + + VecPin vec_pin; + vec_pin.pin_id = pin_id; + vec_pin.pin_name = driver_pin->get_pin_name(); + vec_pin.instance_name = instance_name; + vec_pin.is_driver = true; + vec_net->addPin(pin_id, vec_pin); + + vec_net->addPinId(pin_id); + _layout->add_pin_map(pin_id, instance_name, driver_pin->get_pin_name()); + + pin_id++; + } + + for (auto* load_pin : idb_net->get_load_pins()) { + auto instance_name = load_pin->is_io_pin() ? "" : load_pin->get_instance()->get_name(); + + VecPin vec_pin; + vec_pin.pin_id = pin_id; + vec_pin.pin_name = load_pin->get_pin_name(); + vec_pin.instance_name = instance_name; + vec_pin.is_driver = false; + vec_net->addPin(pin_id, vec_pin); + + vec_net->addPinId(pin_id); + _layout->add_pin_map(pin_id, instance_name, load_pin->get_pin_name()); + + pin_id++; + } + + for (auto* io_pin : idb_net->get_io_pins()->get_pin_list()) { + if (vec_net == nullptr) { + continue; + } + vec_net->addPinId(pin_id); + _layout->add_pin_map(pin_id, "", io_pin->get_pin_name()); + pin_id++; + } + } + +#pragma omp parallel for schedule(dynamic) + for (int net_id = 0; net_id < (int) idb_nets->get_net_list().size(); ++net_id) { + auto* idb_net = idb_nets->get_net_list()[net_id]; + auto* driver_pin = idb_net->get_driving_pin(); + /// ignore net if pin number < 2 and no driver pin + if (idb_net->get_pin_number() < 2 || driver_pin == nullptr) { + continue; + } + + auto* vec_net = graph.get_net(net_id); + + for (auto* idb_inst_pin : idb_net->get_instance_pin_list()->get_pin_list()) { + auto pin_id = _layout->findPinId(idb_inst_pin->get_instance()->get_name(), idb_inst_pin->get_pin_name()); + auto instance_id = _layout->findInstId(idb_inst_pin->get_instance()->get_name()); + transPin(idb_inst_pin, net_id, VecNodeTYpe::vec_net, instance_id, pin_id, false); + } + + for (auto* io_pin : idb_net->get_io_pins()->get_pin_list()) { + auto pin_id = _layout->findPinId("", io_pin->get_pin_name()); + transPin(io_pin, net_id, VecNodeTYpe::vec_net, -1, pin_id, true); + } + + /// init wires + auto* idb_wires = idb_net->get_wire_list(); + for (auto* idb_wire : idb_wires->get_wire_list()) { + for (auto* idb_segment : idb_wire->get_segment_list()) { + /// wire + if (idb_segment->is_via()) { + for (auto* idb_via : idb_segment->get_via_list()) { + transVia(idb_via, net_id, VecNodeTYpe::vec_net); + } + } else if (idb_segment->is_rect()) { + /// wire patch + auto* coordinate = idb_segment->get_point_start(); + auto* rect_delta = idb_segment->get_delta_rect(); + IdbRect* rect = new IdbRect(rect_delta); + rect->moveByStep(coordinate->get_x(), coordinate->get_y()); + + /// build grid + transNetDelta(rect->get_low_x(), rect->get_low_y(), rect->get_high_x(), rect->get_high_y(), idb_segment->get_layer()->get_name(), + net_id, VecNodeTYpe::vec_net); + + delete rect; + } else { + /// nothing to do + } + + /// build wire + if (idb_segment->get_point_number() >= 2) { + auto* routing_layer = dynamic_cast(idb_segment->get_layer()); + + /// get bounding box + auto* point_1 = idb_segment->get_point_start(); + auto* point_2 = idb_segment->get_point_second(); + + int32_t ll_x = std::min(point_1->get_x(), point_2->get_x()); + int32_t ll_y = std::min(point_1->get_y(), point_2->get_y()); + int32_t ur_x = std::max(point_1->get_x(), point_2->get_x()); + int32_t ur_y = std::max(point_1->get_y(), point_2->get_y()); + + /// build grid + transNetRect(ll_x, ll_y, ur_x, ur_y, routing_layer->get_name(), net_id, VecNodeTYpe::vec_net); + } + } + if (net_id % 1000 == 0) { + LOG_INFO << "Read nets : " << net_id << " / " << (int) idb_nets->get_net_list().size(); + } + } + } + + LOG_INFO << "Read nets : " << idb_nets->get_net_list().size() << " / " << (int) idb_nets->get_net_list().size(); + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + + LOG_INFO << "Vectorization init nets end..."; +} + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/layout/data_manager/vec_layout_init.h b/src/vectorization/src/layout/data_manager/vec_layout_init.h new file mode 100644 index 0000000000000000000000000000000000000000..772d014dbcc146ec30cb22d94ac242b968a01ae2 --- /dev/null +++ b/src/vectorization/src/layout/data_manager/vec_layout_init.h @@ -0,0 +1,62 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "IdbGeometry.h" +#include "IdbLayerShape.h" +#include "IdbPins.h" +#include "IdbTrackGrid.h" +#include "IdbVias.h" +#include "vec_layer_grid.h" +#include "vec_layout.h" + +namespace ivec { + +class VecLayoutInit +{ + public: + VecLayoutInit(VecLayout* layout) : _layout(layout) {} + ~VecLayoutInit() {} + void init(); + + private: + VecLayout* _layout; + int64_t _node_id = 0; + int error_pin_num = 0; + + void initViaIds(); + void initDie(); + void initLayers(); + void initCells(); + void initTracks(); + void initTrackGrid(idb::IdbTrackGrid* idb_track_grid); + void buildLayoutGrid(); + void initPDN(); + void initInstances(); + void initIOPins(); + void initNets(); + + void transPin(idb::IdbPin* idb_pin, int net_id, VecNodeTYpe type, int instance_id = -1, int pin_id = -1, bool b_io = false); + void transVia(idb::IdbVia* idb_via, int net_id, VecNodeTYpe type); + void transEnclosure(int32_t ll_x, int32_t ll_y, int32_t ur_x, int32_t ur_y, std::string layer_name, int net_id, int via_row, int via_col, + VecNodeTYpe type); + void transNetRect(int32_t ll_x, int32_t ll_y, int32_t ur_x, int32_t ur_y, std::string layer_name, int net_id, VecNodeTYpe type); + void transNetDelta(int32_t ll_x, int32_t ll_y, int32_t ur_x, int32_t ur_y, std::string layer_name, int net_id, VecNodeTYpe type); +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/layout/data_manager/vec_pattern_gen.cc b/src/vectorization/src/layout/data_manager/vec_pattern_gen.cc new file mode 100644 index 0000000000000000000000000000000000000000..ed9bb4f0667e53f9a80b3bf181062bf99eb6c1f9 --- /dev/null +++ b/src/vectorization/src/layout/data_manager/vec_pattern_gen.cc @@ -0,0 +1,280 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file vec_pattern_gen.cc + * @author Dawn Li (dawnli619215645@gmail.com) + * @version 1.0 + * @date 2024-11-25 + * @brief pattern generation for vectorization + */ + +#include "vec_pattern_gen.hh" + +#include +#include + +#include "log/Log.hh" + +namespace ivec { + +std::vector VecPatternGenerator::generateAllPatterns(const int& w, const int& h) +{ + // Initialize the state with a 1x1 grid + PatternState initial; + initial.grid = Matrix::Zero(1, 1); + initial.grid(0, 0) = 1; + initial.current_row = 0; + initial.current_col = 0; + initial.max_width = 1; + initial.max_height = 1; + initial.val = 1; + + std::vector results; + + // Directions to start, just need to start from top-bottom-right, because of symmetry + std::vector directions = {kTOP, kBOTTOM, kRIGHT}; + std::vector t_b_r; + generatePatterns(w, h, directions, initial, t_b_r); + std::ranges::copy(t_b_r, std::back_inserter(results)); + + // Generate top-bottom-left patterns by horizontal reversing + auto t_b_l = std::ranges::transform_view(t_b_r, [](const Matrix& matrix) { return reverse(matrix, true, false); }); + std::ranges::copy(t_b_l, std::back_inserter(results)); + + // Generate left-right-top patterns by rotating 90 degrees (counter-clockwise) + auto l_r_t = std::ranges::transform_view(t_b_r, [](const Matrix& matrix) { return rotate(matrix, 90); }); + std::ranges::copy(l_r_t, std::back_inserter(results)); + + // Generate left-right-bottom patterns by rotating 90 degrees (counter-clockwise) + auto l_r_b = std::ranges::transform_view(t_b_l, [](const Matrix& matrix) { return rotate(matrix, 90); }); + std::ranges::copy(l_r_b, std::back_inserter(results)); + + // Drop duplicate patterns/matrices + dropDuplicatePatterns(results); + + return results; +} + +bool VecPatternGenerator::isFeasible(const PatternState& state, const PatternDirection& dir) +{ + // if cuurent row/col is not enough to expand, return true + switch (dir) { + case kTOP: + if (state.current_row == 0) { + return true; + } + return state.grid(state.current_row - 1, state.current_col) == 0; + break; + case kBOTTOM: + if (state.current_row == state.max_height - 1) { + return true; + } + return state.grid(state.current_row + 1, state.current_col) == 0; + break; + case kLEFT: + if (state.current_col == 0) { + return true; + } + return state.grid(state.current_row, state.current_col - 1) == 0; + break; + case kRIGHT: + if (state.current_col == state.max_width - 1) { + return true; + } + return state.grid(state.current_row, state.current_col + 1) == 0; + break; + } + return false; +} + +Matrix VecPatternGenerator::reverse(const Matrix& matrix, const bool& horizontal, const bool& vertical) +{ + auto reversed = matrix; + if (horizontal) { + reversed = reversed.rowwise().reverse(); + } + if (vertical) { + reversed = reversed.colwise().reverse(); + } + return reversed; +} + +Matrix VecPatternGenerator::rotate(const Matrix& matrix, const int& angle) +{ + // angle must be a multiple of 90 + LOG_FATAL_IF(angle % 90 != 0) << "Angle must be a multiple of 90"; + + // Calculate the number of 90-degree rotations + int num_rotations = angle / 90; + Matrix rotated = matrix; + + // Rotate the matrix + for (int i = 0; i < num_rotations; ++i) { + rotated = rotated.transpose().colwise().reverse(); + } + + // rotate 90 degrees counter-clockwise + return rotated; +} + +PatternState VecPatternGenerator::expandGrid(const PatternState& state, const PatternDirection& dir) +{ + auto new_state = state; + new_state.val += 1; + + // Expand the grid based on the direction + switch (dir) { + case kTOP: + if (new_state.current_row == 0) { + // Add a row at the top + Matrix new_grid(state.grid.rows() + 1, state.grid.cols()); + new_grid.setZero(); + new_grid.block(1, 0, state.grid.rows(), state.grid.cols()) = state.grid; + new_state.grid = new_grid; + new_state.current_row += 1; + new_state.max_height += 1; + } + break; + case kBOTTOM: + if (new_state.current_row == new_state.max_height - 1) { + // Add a row at the bottom + Matrix new_grid(state.grid.rows() + 1, state.grid.cols()); + new_grid.setZero(); + new_grid.block(0, 0, state.grid.rows(), state.grid.cols()) = state.grid; + new_state.grid = new_grid; + new_state.max_height += 1; + } + break; + case kLEFT: + if (new_state.current_col == 0) { + // Add a column on the left + Matrix new_grid(state.grid.rows(), state.grid.cols() + 1); + new_grid.setZero(); + new_grid.block(0, 1, state.grid.rows(), state.grid.cols()) = state.grid; + new_state.grid = new_grid; + new_state.current_col += 1; + new_state.max_width += 1; + } + break; + case kRIGHT: + if (new_state.current_col == new_state.max_width - 1) { + // Add a column on the right + Matrix new_grid(state.grid.rows(), state.grid.cols() + 1); + new_grid.setZero(); + new_grid.block(0, 0, state.grid.rows(), state.grid.cols()) = state.grid; + new_state.grid = new_grid; + new_state.max_width += 1; + } + break; + } + + return new_state; +} + +void VecPatternGenerator::generatePatterns(const int& w, const int& h, const std::vector& directions, + const PatternState& current, std::vector& results) +{ + // Add the current grid to results, if it's not 1x1 + if (current.max_width > 1 || current.max_height > 1) { + results.push_back(current.grid); + } + + // Try all four possible directions + for (auto& dir : directions) { + if (!isFeasible(current, dir)) { + continue; + } + auto new_state = expandGrid(current, dir); + + // Check if expansion is within limits + if (new_state.max_width > w || new_state.max_height > h) { + continue; + } + + // Find the new position to add the pattern + switch (dir) { + case kTOP: + if (new_state.grid(current.current_row - 1, current.current_col) == 0) { + new_state.grid(current.current_row - 1, current.current_col) = new_state.val; + new_state.current_row -= 1; + } + break; + case kBOTTOM: + if (new_state.grid(current.current_row + 1, current.current_col) == 0) { + new_state.grid(current.current_row + 1, current.current_col) = new_state.val; + new_state.current_row += 1; + } + break; + case kLEFT: + if (new_state.grid(current.current_row, current.current_col - 1) == 0) { + new_state.grid(current.current_row, current.current_col - 1) = new_state.val; + new_state.current_col -= 1; + } + break; + case kRIGHT: + if (new_state.grid(current.current_row, current.current_col + 1) == 0) { + new_state.grid(current.current_row, current.current_col + 1) = new_state.val; + new_state.current_col += 1; + } + break; + } + + // Recursive call + generatePatterns(w, h, directions, new_state, results); + } +} + +void VecPatternGenerator::dropDuplicatePatterns(std::vector& results) +{ + // Lambda function to convert a matrix to a string, split by ',' and ';' + auto to_string = [](const Matrix& matrix) { + std::string pattern_str; + for (int i = 0; i < matrix.rows(); ++i) { + for (int j = 0; j < matrix.cols(); ++j) { + pattern_str += std::to_string(matrix(i, j)); + if (j < matrix.cols() - 1) { + pattern_str += ","; + } + } + if (i < matrix.rows() - 1) { + pattern_str += ";"; + } + } + return pattern_str; + }; + + // Use a set to store unique patterns + std::unordered_set unique_matrices; + std::vector to_remove; + + for (size_t i = 0; i < results.size(); ++i) { + auto pattern_str = to_string(results[i]); + if (unique_matrices.contains(pattern_str)) { + to_remove.push_back(i); + } else { + unique_matrices.insert(pattern_str); + } + } + + // Remove duplicate patterns + for (size_t i = to_remove.size(); i > 0; --i) { + results.erase(results.begin() + to_remove[i - 1]); + } + + return; +} +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/layout/data_manager/vec_pattern_gen.hh b/src/vectorization/src/layout/data_manager/vec_pattern_gen.hh new file mode 100644 index 0000000000000000000000000000000000000000..160d41da0e4e7912cf1da5fd49d41ad34635861e --- /dev/null +++ b/src/vectorization/src/layout/data_manager/vec_pattern_gen.hh @@ -0,0 +1,82 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file vec_pattern_gen.hh + * @author Dawn Li (dawnli619215645@gmail.com) + * @version 1.0 + * @date 2024-11-25 + * @brief pattern generation for vectorization + */ + +#pragma once + +#include +#include +#include + +namespace ivec { +using Matrix = Eigen::Matrix; +// Structure to hold the current state +struct PatternState +{ + Matrix grid; + int current_row; + int current_col; + int max_width; + int max_height; + int val; +}; + +// Directions for expansion +enum PatternDirection +{ + kTOP, + kBOTTOM, + kLEFT, + kRIGHT +}; + +class VecPatternGenerator +{ + public: + VecPatternGenerator() = delete; + ~VecPatternGenerator() {} + + // Main function to initiate pattern generation + static std::vector generateAllPatterns(const int& w, const int& h); + + private: + // Check Direction Feasibility + static bool isFeasible(const PatternState& state, const PatternDirection& dir); + + // Reverse Operation + static Matrix reverse(const Matrix& matrix, const bool& horizontal, const bool& vertical); + + // Rotate Operation + static Matrix rotate(const Matrix& matrix, const int& angle); + + // Function to deep copy the grid and expand it in the specified direction + static PatternState expandGrid(const PatternState& state, const PatternDirection& dir); + + // Recursive function to generate all patterns + static void generatePatterns(const int& w, const int& h, const std::vector& directions, const PatternState& current, + std::vector& results); + + // Drop duplicate patterns + static void dropDuplicatePatterns(std::vector& results); +}; +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/layout/data_manager/vec_wire_pattern.cc b/src/vectorization/src/layout/data_manager/vec_wire_pattern.cc new file mode 100644 index 0000000000000000000000000000000000000000..02484af5b29fb138bb6c19f06b9514c591158e37 --- /dev/null +++ b/src/vectorization/src/layout/data_manager/vec_wire_pattern.cc @@ -0,0 +1,163 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file vec_wire_pattern.cc + * @author Dawn Li (dawnli619215645@gmail.com) + * @version 1.0 + * @date 2024-12-08 + * @brief wire pattern for vectorization + */ + +#include "vec_wire_pattern.hh" + +#include +#include +#include +#include + +#include "log/Log.hh" +#include "vec_net_graph_gen.hh" +namespace ivec { +void VecWirePatternGenerator::genPatterns() +{ + auto gen = VecNetGraphGenerator(); + auto graphs = gen.buildGraphs(); + auto build_pattern = [&](auto& edge, auto& graph) { + auto path = graph[edge].path; + std::vector points; + for (auto& [start, end] : path) { + auto start_point = Point{bg::get<0>(start), bg::get<1>(start), bg::get<2>(start)}; + points.push_back(start_point); + } + auto end = path.back().second; + points.push_back(Point{bg::get<0>(end), bg::get<1>(end), bg::get<2>(end)}); + auto pattern = calcPattern(points); + if (_pattern_count.contains(pattern.name)) { + _pattern_count[pattern.name] += 1; + } else { + _patterns[pattern.name] = pattern; + _pattern_count[pattern.name] = 1; + } + }; + std::ranges::for_each(graphs, [&](auto& graph) { + for (auto e : boost::make_iterator_range(boost::edges(graph))) { + build_pattern(e, graph); + } + }); +} +void VecWirePatternGenerator::addPattern(VecNetWire& wire) +{ + auto points = getPointList(wire); + auto pattern = calcPattern(points); + if (_pattern_count.contains(pattern.name)) { + _pattern_count[pattern.name] += 1; + } else { + _patterns[pattern.name] = pattern; + _pattern_count[pattern.name] = 1; + } +} + +void VecWirePatternGenerator::patternSummary(const std::string& csv_path) +{ + std::ofstream csv_file(csv_path); + csv_file << "Pattern,Count\n"; + for (auto& [pattern, count] : _pattern_count) { + csv_file << pattern << "," << count << "\n"; + } +} + +std::vector VecWirePatternGenerator::getPointList(VecNetWire& wire) +{ + auto& path = wire.get_paths(); + std::vector points; + for (auto& [start, end] : path) { + auto start_point = Point{start->get_x(), start->get_y(), start->get_layer_id()}; + points.push_back(start_point); + } + auto end = path.back().second; + points.push_back(Point{end->get_x(), end->get_y(), end->get_layer_id()}); + return points; +} + +VecWirePatternSequence VecWirePatternGenerator::calcPattern(const std::vector& points) +{ + // make front in the top-right corner, reverse if needed + auto sorted_points = points; + if (sorted_points.front().x > sorted_points.back().x) { + std::ranges::reverse(sorted_points); + } else if (sorted_points.front().x == sorted_points.back().x && sorted_points.front().y > sorted_points.back().y) { + std::ranges::reverse(sorted_points); + } + // init pattern + VecWirePatternSequence pattern; + for (size_t i = 0; i < sorted_points.size() - 1; ++i) { + auto& start = sorted_points[i]; + auto& end = sorted_points[i + 1]; + VecWirePatternUnit unit; + bool x_same = start.x == end.x; + bool y_same = start.y == end.y; + bool z_same = start.z == end.z; + if (x_same && y_same && z_same) { + continue; + } + unit.direction = (x_same && y_same) ? kVIA : (x_same ? (start.y < end.y ? kTOP : kBOTTOM) : (start.x < end.x ? kRIGHT : kLEFT)); + if (unit.direction == kVIA) { + unit.length = 1; + } else { + unit.length = std::abs(start.x - end.x) + std::abs(start.y - end.y); + } + pattern.units.push_back(unit); + } + + if (pattern.units.empty()) { + return pattern; + } + + // post-process + // 1. find the max common factor by gcd + auto max_common_factor = pattern.units.front().length; + std::ranges::for_each(pattern.units, + [&max_common_factor](const auto& unit) { max_common_factor = std::gcd(max_common_factor, unit.length); }); + // 2. normalize the pattern + std::ranges::for_each(pattern.units, [&max_common_factor](auto& unit) { unit.length /= max_common_factor; }); + // 3. generate the pattern name + std::string pattern_name; + std::ranges::for_each(pattern.units, [&pattern_name](const auto& unit) { + switch (unit.direction) { + case kTOP: + pattern_name += "T"; + break; + case kBOTTOM: + pattern_name += "B"; + break; + case kLEFT: + pattern_name += "L"; + break; + case kRIGHT: + pattern_name += "R"; + break; + case kVIA: + pattern_name += "V"; + break; + } + pattern_name += std::to_string(unit.length / 100 + 1); + }); + pattern.name = pattern_name; + return pattern; +} + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/layout/data_manager/vec_wire_pattern.hh b/src/vectorization/src/layout/data_manager/vec_wire_pattern.hh new file mode 100644 index 0000000000000000000000000000000000000000..3557c2b820f2ca254b23ff78fcbb3751d782bc56 --- /dev/null +++ b/src/vectorization/src/layout/data_manager/vec_wire_pattern.hh @@ -0,0 +1,79 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @file vec_wire_pattern.hh + * @author Dawn Li (dawnli619215645@gmail.com) + * @version 1.0 + * @date 2024-12-08 + * @brief wire pattern for vectorization + */ + +#pragma once + +#include +#include +#include + +#include "vec_net.h" + +namespace ivec { +struct Point +{ + int x; + int y; + int z; +}; +enum VecWirePatternDirection +{ + kTOP, + kBOTTOM, + kLEFT, + kRIGHT, + kVIA +}; + +struct VecWirePatternUnit +{ + VecWirePatternDirection direction; + int length; +}; + +struct VecWirePatternSequence +{ + std::string name; + std::vector units; +}; + +class VecWirePatternGenerator +{ + public: + VecWirePatternGenerator() {} + ~VecWirePatternGenerator() {} + + void genPatterns(); + void addPattern(VecNetWire& wire); + void patternSummary(const std::string& csv_path); + + private: + std::vector getPointList(VecNetWire& wire); + VecWirePatternSequence calcPattern(const std::vector& points); + + std::unordered_map _patterns; + std::unordered_map _pattern_count; +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/layout/database/CMakeLists.txt b/src/vectorization/src/layout/database/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..2b44ed33cccf08adbda6e80163accf17dbe717ac --- /dev/null +++ b/src/vectorization/src/layout/database/CMakeLists.txt @@ -0,0 +1,23 @@ +# Find TBB using CMake's standard mechanism +find_package(TBB REQUIRED) + +add_library(ivec_layout_db + vec_layout.cpp + vec_layer.cpp + vec_layer_grid.cpp +) + +target_link_libraries(ivec_layout_db + PUBLIC + log + ivec_db + ivec_util + PRIVATE + TBB::tbb +) + +target_include_directories(ivec_layout_db + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + Eigen3::Eigen +) diff --git a/src/vectorization/src/layout/database/vec_layer.cpp b/src/vectorization/src/layout/database/vec_layer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5069ce5bc6cfc153bfef3c839945feaaed6f999a --- /dev/null +++ b/src/vectorization/src/layout/database/vec_layer.cpp @@ -0,0 +1,73 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "vec_layer.h" + +namespace ivec { +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +VecNet* VecLayoutLayer::get_net(int net_id) +{ + auto it = _net_map.find(net_id); + if (it != _net_map.end()) { + return &it->second; + } + + return nullptr; +} + +VecNet* VecLayoutLayer::getOrCreateNet(int net_id) +{ + auto* net = get_net(net_id); + if (net == nullptr) { + VecNet new_net(net_id); + auto result = _net_map.insert(std::make_pair(net_id, new_net)); + + if (result.first != _net_map.end()) { + return &result.first->second; + } + } + + return net; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +VecLayoutLayer* VecLayoutLayers::findLayoutLayer(int order) +{ + auto layout_layer = _layout_layers.find(order); + if (layout_layer != _layout_layers.end()) { + return &layout_layer->second; + } + + return nullptr; +} + +} // namespace ivec diff --git a/src/vectorization/src/layout/database/vec_layer.h b/src/vectorization/src/layout/database/vec_layer.h new file mode 100644 index 0000000000000000000000000000000000000000..83fad4dd7e60a5ff63a2843698a2da48ed8e3cb4 --- /dev/null +++ b/src/vectorization/src/layout/database/vec_layer.h @@ -0,0 +1,153 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include + +#include "vec_layer_grid.h" +#include "vec_net.h" + +namespace ivec { + +class VecLayoutLayer +{ + public: + VecLayoutLayer() {} + ~VecLayoutLayer() {} + // 添加移动构造函数 + VecLayoutLayer(VecLayoutLayer&& other) noexcept + : _layer_name(std::move(other._layer_name)), + _wire_width(other._wire_width), + _b_routing(other._b_routing), + _b_horizontal(other._b_horizontal), + _layer_order(other._layer_order), + _llx(other._llx), + _lly(other._lly), + _urx(other._urx), + _ury(other._ury), + _row_num(other._row_num), + _row_space(other._row_space), + _col_num(other._col_num), + _col_space(other._col_space), + _grid(std::move(other._grid)), + _net_map(std::move(other._net_map)) + { + } + + // 添加移动赋值运算符 + VecLayoutLayer& operator=(VecLayoutLayer&& other) noexcept + { + if (this != &other) { + _layer_name = std::move(other._layer_name); + _wire_width = other._wire_width; + _b_routing = other._b_routing; + _b_horizontal = other._b_horizontal; + _layer_order = other._layer_order; + _llx = other._llx; + _lly = other._lly; + _urx = other._urx; + _ury = other._ury; + _row_num = other._row_num; + _row_space = other._row_space; + _col_num = other._col_num; + _col_space = other._col_space; + _grid = std::move(other._grid); + _net_map = std::move(other._net_map); + } + return *this; + } + + // getter + std::string& get_layer_name() { return _layer_name; } + int get_wire_width() { return _wire_width; } + bool is_routing() { return _b_routing; } + VecLayerGrid& get_grid() { return _grid; } + + std::map& get_net_map() { return _net_map; } + VecNet* get_net(int net_id); + int get_layer_order() { return _layer_order; } + bool is_horizontal() { return _b_horizontal; } + + // setter + void set_layer_name(std::string name) { _layer_name = name; } + void set_wire_width(int wire_width) { _wire_width = wire_width; } + void set_as_routing(bool b_routing) { _b_routing = b_routing; } + void set_layer_order(int order) { _layer_order = order; } + void set_llx(int value) { _llx = value; } + void set_lly(int value) { _lly = value; } + void set_urx(int value) { _urx = value; } + void set_ury(int value) { _ury = value; } + void set_horizontal(bool b_horizontal) { _b_horizontal = b_horizontal; } + + // operator + VecNet* getOrCreateNet(int net_id); + + private: + std::string _layer_name; + int _wire_width = 0; + bool _b_routing; + bool _b_horizontal; + int _layer_order; + int _llx; + int _lly; + int _urx; + int _ury; + int _row_num; /// row number + int _row_space; + int _col_num; /// col number + int _col_space; + VecLayerGrid _grid; + std::map _net_map; +}; + +class VecLayoutLayers +{ + public: + VecLayoutLayers() {}; + ~VecLayoutLayers() {} + + // getter + int get_layer_order_top() { return _layer_order_top; } + int get_layer_order_bottom() { return _layer_order_bottom; } + std::unordered_map& get_layout_layer_map() { return _layout_layers; } + VecLayoutLayer* findLayoutLayer(int order); + + // setter + void set_layer_order_top(int order) { _layer_order_top = order; } + void set_layer_order_bottom(int order) { _layer_order_bottom = order; } + + // operator + + private: + int _layer_order_top = -1; + int _layer_order_bottom = -1; + std::unordered_map _layout_layers; /// int : layer order +}; + +} // namespace ivec diff --git a/src/vectorization/src/layout/database/vec_layer_grid.cpp b/src/vectorization/src/layout/database/vec_layer_grid.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d70654411224751d5688f03de334a850fa521c9 --- /dev/null +++ b/src/vectorization/src/layout/database/vec_layer_grid.cpp @@ -0,0 +1,119 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "vec_layer_grid.h" + +#include "vec_grid_info.h" + +namespace ivec { +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +VecLayerGrid::~VecLayerGrid() +{ + // for (int row_id = 0; row_id < gridInfoInst.node_row_num; ++row_id) { + // for (int col_id = 0; col_id < gridInfoInst.node_col_num; ++col_id) { + // if (_node_matrix[row_id][col_id] != nullptr) { + // delete _node_matrix[row_id][col_id]; + // _node_matrix[row_id][col_id] = nullptr; + // } + // } + // } + // 释放所有节点 + for (auto& pair : _node_map) { + delete pair.second; + } +} + +std::pair VecLayerGrid::buildNodeMatrix(int order) +{ + gridInfoInst.node_x_start = gridInfoInst.x_start % gridInfoInst.x_step; + gridInfoInst.node_y_start = gridInfoInst.y_start % gridInfoInst.y_step; + + _row_num = (gridInfoInst.ury - gridInfoInst.node_y_start) / gridInfoInst.y_step; + _col_num = (gridInfoInst.urx - gridInfoInst.node_x_start) / gridInfoInst.x_step; + + gridInfoInst.node_row_num = _row_num; + gridInfoInst.node_col_num = _col_num; + + return std::make_pair(_row_num, _col_num); +} + +VecNode* VecLayerGrid::get_node(int row_id, int col_id, bool b_create) +{ + std::pair key = {row_id, col_id}; + + // 尝试查找节点 + auto it = _node_map.find(key); + if (it != _node_map.end()) { + return it->second; + } + + // 如果不存在且不需要创建,返回nullptr + if (!b_create) { + return nullptr; + } + + // 创建新节点 + VecNode* new_node = new VecNode(); + + // 使用原子操作尝试插入 + // insert_or_assign 不适用于 TBB,使用 insert 代替 + auto result = _node_map.insert({key, new_node}); + + if (!result.second) { + // 插入失败,说明其他线程已经创建了节点 + delete new_node; + return result.first->second; + } + + // 插入成功,返回新节点 + return new_node; +} + +VecNode* VecLayerGrid::findNode(int x, int y) +{ + auto [row_id, col_id] = gridInfoInst.findNodeID(x, y); + + return get_node(row_id, col_id); +} + +std::vector VecLayerGrid::get_all_nodes() +{ + std::vector nodes; + nodes.reserve(_node_map.size()); + + for (const auto& pair : _node_map) { + nodes.push_back(pair.second); + } + + return nodes; +} + +} // namespace ivec diff --git a/src/vectorization/src/layout/database/vec_layer_grid.h b/src/vectorization/src/layout/database/vec_layer_grid.h new file mode 100644 index 0000000000000000000000000000000000000000..fea1533065cde1e895b893fecb8dd9cebbe5fb2c --- /dev/null +++ b/src/vectorization/src/layout/database/vec_layer_grid.h @@ -0,0 +1,102 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include + +#include +#include +#include +#include +#include + +#include "vec_node.h" + +namespace ivec { + +// 为 std::unordered_map 定义哈希函数 +struct PairHash +{ + size_t operator()(const std::pair& p) const { return static_cast(p.first) * 16777619u ^ static_cast(p.second); } +}; + +// 为 std::unordered_map 定义相等比较函数 +struct PairEqual +{ + bool operator()(const std::pair& lhs, const std::pair& rhs) const + { + return lhs.first == rhs.first && lhs.second == rhs.second; + } +}; + +class VecLayerGrid +{ + public: + VecLayerGrid() {} + ~VecLayerGrid(); + // 添加移动构造函数 + VecLayerGrid(VecLayerGrid&& other) noexcept + : layer_order(other.layer_order), _node_map(std::move(other._node_map)), _row_num(other._row_num), _col_num(other._col_num) + { + } + + // 添加移动赋值运算符 + VecLayerGrid& operator=(VecLayerGrid&& other) noexcept + { + if (this != &other) { + // 释放当前资源 + for (auto& pair : _node_map) { + delete pair.second; + } + layer_order = other.layer_order; + _node_map = std::move(other._node_map); + _row_num = other._row_num; + _col_num = other._col_num; + } + return *this; + } + + // getter 无锁版 + VecNode* get_node(int row_id, int col_id, bool b_create = false); + std::vector get_all_nodes(); + // setter + + // operator + std::pair buildNodeMatrix(int order); + VecNode* findNode(int x, int y); + + public: + int layer_order; + + private: + // 使用 TBB 的并发哈希表 + tbb::concurrent_unordered_map, VecNode*, PairHash, PairEqual> _node_map; + int _row_num; + int _col_num; +}; + +} // namespace ivec diff --git a/src/vectorization/src/layout/database/vec_layout.cpp b/src/vectorization/src/layout/database/vec_layout.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1fe606c6a7dfe0475acdc5f98376088b31d50fa --- /dev/null +++ b/src/vectorization/src/layout/database/vec_layout.cpp @@ -0,0 +1,214 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "vec_layout.h" + +namespace ivec { + +void VecLayout::add_cell(VecCell cell) +{ + _cells.addCell(cell); + + _cell_name_map.insert(std::make_pair(cell.name, cell.id)); +} + +void VecLayout::add_instance(VecInstance instance) +{ + _instances.addInstance(instance); +} + +void VecLayout::add_layer_map(int id, std::string name) +{ + _layer_name_map.insert(std::make_pair(name, id)); + _layer_id_map.insert(std::make_pair(id, name)); +} + +void VecLayout::add_via_map(int id, std::string name) +{ + _via_name_map.insert(std::make_pair(name, id)); + _via_id_map.insert(std::make_pair(id, name)); +} + +void VecLayout::add_pdn_map(int id, std::string name) +{ + _pdn_name_map.insert(std::make_pair(name, id)); + _pdn_id_map.insert(std::make_pair(id, name)); +} + +void VecLayout::add_net_map(int id, std::string name) +{ + _net_name_map.insert(std::make_pair(name, id)); + _net_id_map.insert(std::make_pair(id, name)); +} + +void VecLayout::add_pin_map(int id, std::string inst_name, std::string pin_name) +{ + auto name_pair = std::make_pair(inst_name, pin_name); + _pin_name_map.insert(std::make_pair(name_pair, id)); + _pin_id_map.insert(std::make_pair(id, name_pair)); +} + +void VecLayout::add_instance_map(int id, std::string name) +{ + _inst_name_map.insert(std::make_pair(name, id)); + _inst_id_map.insert(std::make_pair(id, name)); +} + +int VecLayout::findLayerId(std::string name) +{ + auto it = _layer_name_map.find(name); + if (it != _layer_name_map.end()) { + return it->second; + } + + return -1; +} + +std::string VecLayout::findLayerName(int id) +{ + auto it = _layer_id_map.find(id); + if (it != _layer_id_map.end()) { + return it->second; + } + + return ""; +} + +int VecLayout::findViaId(std::string name) +{ + auto it = _via_name_map.find(name); + if (it != _via_name_map.end()) { + return it->second; + } + + return -1; +} + +std::string VecLayout::findViaName(int id) +{ + auto it = _via_id_map.find(id); + if (it != _via_id_map.end()) { + return it->second; + } + + return ""; +} + +int VecLayout::findPdnId(std::string name) +{ + auto it = _pdn_name_map.find(name); + if (it != _pdn_name_map.end()) { + return it->second; + } + + return -1; +} + +std::string VecLayout::findPdnName(int id) +{ + auto it = _pdn_id_map.find(id); + if (it != _pdn_id_map.end()) { + return it->second; + } + + return ""; +} + +int VecLayout::findNetId(std::string name) +{ + auto it = _net_name_map.find(name); + if (it != _net_name_map.end()) { + return it->second; + } + + return -1; +} + +std::string VecLayout::findNetName(int id) +{ + auto it = _net_id_map.find(id); + if (it != _net_id_map.end()) { + return it->second; + } + + return ""; +} + +int VecLayout::findPinId(std::string inst_name, std::string pin_name) +{ + auto name_pair = std::make_pair(inst_name, pin_name); + auto it = _pin_name_map.find(name_pair); + if (it != _pin_name_map.end()) { + return it->second; + } + + return -1; +} +/// @brief +/// @param id +/// @return first : instance name, second : pin name +std::pair VecLayout::findPinName(int id) +{ + auto it = _pin_id_map.find(id); + if (it != _pin_id_map.end()) { + return it->second; + } + + return std::make_pair("", ""); +} + +int VecLayout::findInstId(std::string name) +{ + auto it = _inst_name_map.find(name); + if (it != _inst_name_map.end()) { + return it->second; + } + + return -1; +} + +std::string VecLayout::findInstName(int id) +{ + auto it = _inst_id_map.find(id); + if (it != _inst_id_map.end()) { + return it->second; + } + + return ""; +} + +int VecLayout::findCellId(std::string name) +{ + auto it = _cell_name_map.find(name); + if (it != _cell_name_map.end()) { + return it->second; + } + + return -1; +} + +} // namespace ivec diff --git a/src/vectorization/src/layout/database/vec_layout.h b/src/vectorization/src/layout/database/vec_layout.h new file mode 100644 index 0000000000000000000000000000000000000000..0f3c8c0dd70dbf3075bcab5f2139a7de3d6e1957 --- /dev/null +++ b/src/vectorization/src/layout/database/vec_layout.h @@ -0,0 +1,105 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ +#include +#include +#include + +#include "vec_cell.h" +#include "vec_instance.h" +#include "vec_layer.h" +#include "vec_net.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace ivec { + +class VecLayout +{ + public: + VecLayout() {} + ~VecLayout() {} + + // getter + VecLayoutLayers& get_layout_layers() { return _layout_layers; } + std::map& get_net_name_map() { return _net_name_map; } + VecGraph& get_graph() { return _graph; } + VecCells& get_cells() { return _cells; } + VecInstances& get_instances() { return _instances; } + + // setter + void add_cell(VecCell cell); + void add_instance(VecInstance instance); + void add_layer_map(int id, std::string name); + void add_via_map(int id, std::string name); + void add_pdn_map(int id, std::string name); + void add_net_map(int id, std::string name); + void add_pin_map(int id, std::string inst_name, std::string pin_name); + void add_instance_map(int id, std::string name); + + // operator + int findLayerId(std::string name); + std::string findLayerName(int id); + int findViaId(std::string name); + std::string findViaName(int id); + int findPdnId(std::string name); + std::string findPdnName(int id); + int findNetId(std::string name); + std::string findNetName(int id); + int findPinId(std::string inst_name, std::string pin_name); + std::pair findPinName(int id); + int findInstId(std::string name); + std::string findInstName(int id); + int findCellId(std::string name); + + private: + VecCells _cells; + VecInstances _instances; + + VecLayoutLayers _layout_layers; + + std::map _layer_name_map; /// string : layer name, int : layer id begin from 1st routing layer, for example, if M1 is + /// 1st routing layer, then M1 id=0, CUT1 id=1, M2 id=2 ... + std::map _layer_id_map; /// string : layer name, int : layer id begin from 1st routing layer, for example, if M1 is + /// 1st routing layer, then M1 id=0, CUT1 id=1, M2 id=2 ... + std::map _via_name_map; /// string : via name, int : via index in this map + std::map _via_id_map; /// string : via name, int : via index in this map + std::map _pdn_name_map; /// string : pdn name, int : id in the map + std::map _pdn_id_map; /// string : pdn name, int : id in the map + std::map _net_name_map; /// string : net name, int id in the map + std::map _net_id_map; /// string : net name, int id in the map + std::map, int> + _pin_name_map; /// std::pair : instance name & pin name, int id in the map + std::map> + _pin_id_map; /// std::pair : instance name & pin name, int id in the map + std::map _inst_name_map; /// string : instance name, int id in the map + std::map _inst_id_map; /// string : instance name, int id in the map + std::map _cell_name_map; /// string : cell name, int id in the map + + VecGraph _graph; +}; + +} // namespace ivec diff --git a/src/vectorization/src/patch/CMakeLists.txt b/src/vectorization/src/patch/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bfd22500c32cc39251c5cc41b3f4ef52b63b66f5 --- /dev/null +++ b/src/vectorization/src/patch/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(database) +add_subdirectory(data_manager) \ No newline at end of file diff --git a/src/vectorization/src/patch/data_manager/CMakeLists.txt b/src/vectorization/src/patch/data_manager/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6ee6836dfedf57791a866c69a9bf73ceca60da95 --- /dev/null +++ b/src/vectorization/src/patch/data_manager/CMakeLists.txt @@ -0,0 +1,26 @@ +add_library(ivec_patch_dm + vec_patch_dm.cpp + vec_patch_init.cpp +) + +target_link_libraries(ivec_patch_dm + PUBLIC + idb + idm + geometry_db + log + usage + ivec_db + ivec_patch_db + ivec_layout_db + ivec_util +) + +target_include_directories(ivec_patch_dm + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${HOME_UTILITY}/json + ${OpenCV_INCLUDE_DIRS} +) + +include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) \ No newline at end of file diff --git a/src/vectorization/src/patch/data_manager/vec_patch_dm.cpp b/src/vectorization/src/patch/data_manager/vec_patch_dm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ade78f7a47a27aae2bee1954fad982edbdadfce6 --- /dev/null +++ b/src/vectorization/src/patch/data_manager/vec_patch_dm.cpp @@ -0,0 +1,57 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** + +#include "Log.hh" +#include "omp.h" +#include "usage.hh" +#include "vec_patch_dm.h" +#include "vec_patch_init.h" +#include "vec_grid_info.h" + +namespace ivec { + +bool VecPatchDataManager::buildPatchData() +{ + init(); + + return true; +} + +bool VecPatchDataManager::buildPatchData(int patch_row_step, int patch_col_step) +{ + init(patch_row_step, patch_col_step); + + return true; +} + + +void VecPatchDataManager::init() +{ + VecPatchInit patch_init(_layout, &_patch_grid); + patch_init.init(); +} + +void VecPatchDataManager::init(int patch_row_step, int patch_col_step) +{ + VecPatchInfo::getInst(patch_row_step, patch_col_step); + + VecPatchInit patch_init(_layout, &_patch_grid); + patch_init.init(); +} + + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/patch/data_manager/vec_patch_dm.h b/src/vectorization/src/patch/data_manager/vec_patch_dm.h new file mode 100644 index 0000000000000000000000000000000000000000..fc45638b8c442a7c5bf0f3518504ad3f099e6998 --- /dev/null +++ b/src/vectorization/src/patch/data_manager/vec_patch_dm.h @@ -0,0 +1,45 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "vec_layout.h" +#include "vec_net.h" +#include "vec_patch_grid.h" + +namespace ivec { + +class VecPatchDataManager +{ + public: + VecPatchDataManager(VecLayout* layout) { _layout = layout; } + ~VecPatchDataManager() {} + + VecPatchGrid& get_patch_grid() { return _patch_grid; } + + bool buildPatchData(); + bool buildPatchData(int patch_row_step, int patch_col_step); + + private: + VecLayout* _layout = nullptr; + VecPatchGrid _patch_grid; + + void init(); + void init(int patch_row_step, int patch_col_step); +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/patch/data_manager/vec_patch_init.cpp b/src/vectorization/src/patch/data_manager/vec_patch_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e190c4ab42bacfe01b0e77ab53b81e888385646 --- /dev/null +++ b/src/vectorization/src/patch/data_manager/vec_patch_init.cpp @@ -0,0 +1,303 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** + +#include "vec_patch_init.h" + +#include "Log.hh" +#include "omp.h" +#include "usage.hh" +#include "vec_grid_info.h" +#include "vec_net.h" + +namespace ivec { + +void VecPatchInit::init() +{ + init_patch_grid(); + initSubNet(); +} + +void VecPatchInit::init_patch_grid() +{ + auto init_patch = [&](int patch_row, int patch_col) -> VecPatch { + VecPatch im_patch; + + /// build node id range + if (patchInfoInst.patch_row_start == 0) { + im_patch.rowIdMin = patch_row * patchInfoInst.patch_row_step; + im_patch.rowIdMax = (patch_row + 1) * patchInfoInst.patch_row_step; + im_patch.rowIdMax = im_patch.rowIdMax > gridInfoInst.node_row_num ? gridInfoInst.node_row_num : im_patch.rowIdMax; + } else { + if (patch_row == 0) { + im_patch.rowIdMin = 0; + im_patch.rowIdMax = patchInfoInst.patch_row_start; + } else { + im_patch.rowIdMin = patchInfoInst.patch_row_start + (patch_row - 1) * patchInfoInst.patch_row_step; + im_patch.rowIdMax = patchInfoInst.patch_row_start + patch_row * patchInfoInst.patch_row_step; + } + } + + if (patchInfoInst.patch_col_start == 0) { + im_patch.colIdMin = patch_col * patchInfoInst.patch_col_step; + im_patch.colIdMax = (patch_col + 1) * patchInfoInst.patch_col_step; + im_patch.colIdMax = im_patch.colIdMax > gridInfoInst.node_col_num ? gridInfoInst.node_col_num : im_patch.colIdMax; + } else { + if (patch_col == 0) { + im_patch.colIdMin = 0; + im_patch.colIdMax = patchInfoInst.patch_col_start; + } else { + im_patch.colIdMin = patchInfoInst.patch_col_start + (patch_col - 1) * patchInfoInst.patch_col_step; + im_patch.colIdMax = patchInfoInst.patch_col_start + patch_col * patchInfoInst.patch_col_step; + } + } + + /// build layer + auto& patch_layer_map = im_patch.get_layer_map(); + auto& layers = _layout->get_layout_layers(); + for (int layer_id = layers.get_layer_order_bottom(); layer_id <= layers.get_layer_order_top(); ++layer_id) { + VecPatchLayer patch_layer; + patch_layer.layer_id = layer_id; + patch_layer.rowIdMin = im_patch.rowIdMin; + patch_layer.rowIdMax = im_patch.rowIdMax; + patch_layer.colIdMin = im_patch.colIdMin; + patch_layer.colIdMax = im_patch.colIdMax; + + patch_layer_map.insert(std::make_pair(layer_id, patch_layer)); + } + + return im_patch; + }; + + ieda::Stats stats; + + LOG_INFO << "Vectorization patch grid init start..."; + + auto& patchs = _patch_grid->get_patchs(); + auto& patch_xy_map = _patch_grid->get_patch_xy_map(); + + for (int row = 0; row < patchInfoInst.patch_num_vertical; ++row) { + for (int col = 0; col < patchInfoInst.patch_num_horizontal; ++col) { + auto im_patch = init_patch(row, col); + auto patch_id = patchInfoInst.patch_num_horizontal * row + col; + + im_patch.patch_id = patch_id; + im_patch.patch_id_row = row; + im_patch.patch_id_col = col; + patchs.insert(std::make_pair(patch_id, im_patch)); + + std::pair lx_ly = gridInfoInst.get_node_coodinate(im_patch.rowIdMin, im_patch.colIdMin); + std::pair ux_uy = gridInfoInst.get_node_coodinate(im_patch.rowIdMax, im_patch.colIdMax); + patch_xy_map[patch_id] = std::make_pair(lx_ly, ux_uy); + + if (patch_id % 1000 == 0) { + LOG_INFO << "Init patch : " << patch_id; + } + } + } + + LOG_INFO << "Init patch : " << patchInfoInst.patch_num_vertical * patchInfoInst.patch_num_horizontal; + + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization patch grid init end..."; +} + +void VecPatchInit::initSubNet() +{ + ieda::Stats stats; + + LOG_INFO << "Vectorization patch init subnet start..."; + + omp_lock_t lck; + omp_init_lock(&lck); + + auto& net_map = _layout->get_graph().get_net_map(); +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < (int) net_map.size(); ++i) { + auto it = net_map.begin(); + std::advance(it, i); + auto& net_id = it->first; + auto& vec_net = it->second; + /// wires + for (auto& wire : vec_net.get_wires()) { + /// split paths to patchs + for (auto& [node1, node2] : wire.get_paths()) { + if (node1->get_layer_id() == node2->get_layer_id()) { + /// metal + auto node_map = splitWirePath(node1, node2); + for (auto& [patch_id, split_nodes] : node_map) { + auto* patch = _patch_grid->findPatch(patch_id); + auto* patch_layer = patch->findLayer(node1->get_layer_id()); + if (patch_layer->findNet(net_id) == nullptr) { + omp_set_lock(&lck); + + patch_layer->addSubnet(net_id, wire.get_id(), split_nodes.first, split_nodes.second); + + omp_unset_lock(&lck); + } else { + patch_layer->addSubnet(net_id, wire.get_id(), split_nodes.first, split_nodes.second); + } + + /// label at wire + wire.addPatch(patch_id, node1->get_layer_id()); + } + } else { + /// via ??? no need to store in patch??? + int patch_id = patchInfoInst.get_patch_id(node1->get_row_id(), node1->get_col_id()); + auto* patch = _patch_grid->findPatch(patch_id); + + for (auto node_pair : {std::make_pair(node1, node1), std::make_pair(node1, node2), std::make_pair(node2, node2)}) { + int layer_id = (node_pair.first->get_layer_id() + node_pair.second->get_layer_id()) / 2; + auto* patch_layer = patch->findLayer(layer_id); + auto sub_net = patch_layer->findNet(net_id); + if (sub_net == nullptr) { + omp_set_lock(&lck); + + patch_layer->addSubnet(net_id, wire.get_id(), node_pair.first, node_pair.second); + + omp_unset_lock(&lck); + } else { + patch_layer->addSubnet(sub_net, wire.get_id(), node_pair.first, node_pair.second); + } + + /// label at wire + wire.addPatch(patch_id, layer_id); + } + } + } + } + + omp_set_lock(&lck); + + omp_unset_lock(&lck); + + if (i % 1000 == 0) { + LOG_INFO << "Init net : " << i << " / " << net_map.size(); + } + } + LOG_INFO << "Init net : " << net_map.size() << " / " << net_map.size(); + + omp_destroy_lock(&lck); + + LOG_INFO << "Vectorization memory usage " << stats.memoryDelta() << " MB"; + LOG_INFO << "Vectorization elapsed time " << stats.elapsedRunTime() << " s"; + LOG_INFO << "Vectorization patch init subnet end..."; +} + +std::map> VecPatchInit::splitWirePath(VecNode* node1, VecNode* node2) +{ + std::map> node_map; + if (node1->get_layer_id() == node2->get_layer_id()) { + auto& node_grid = _layout->get_layout_layers().findLayoutLayer(node1->get_layer_id())->get_grid(); + + int row_min = std::min(node1->get_row_id(), node2->get_row_id()); + int row_max = std::max(node1->get_row_id(), node2->get_row_id()); + int col_min = std::min(node1->get_col_id(), node2->get_col_id()); + int col_max = std::max(node1->get_col_id(), node2->get_col_id()); + + if (row_min == row_max) { + /// horizontal + int patch_row_id = patchInfoInst.get_patch_row_id(row_min); + int patch_id_min = patchInfoInst.get_patch_col_id(col_min); + int patch_id_max = patchInfoInst.get_patch_col_id(col_max); + for (int patch_col_id = patch_id_min; patch_col_id <= patch_id_max; ++patch_col_id) { + auto [split_node_id_min, split_node_id_max] = patchInfoInst.get_node_range(patch_col_id, true); + + if (patch_col_id == patch_id_min) { + split_node_id_min = col_min; + } + + if (patch_col_id == patch_id_max) { + split_node_id_max = col_max; + } + + int patch_id = patchInfoInst.patch_num_horizontal * patch_row_id + patch_col_id; + + auto* split_node_1 = node_grid.get_node(row_min, split_node_id_min); + auto* split_node_2 = node_grid.get_node(row_min, split_node_id_max); + if (split_node_1 == nullptr || split_node_2 == nullptr) { + LOG_ERROR << "Node error after split wire"; + } + node_map.emplace(patch_id, std::make_pair(split_node_1, split_node_2)); + } + } else { + /// vertical + int patch_id_min = patchInfoInst.get_patch_row_id(row_min); + int patch_id_max = patchInfoInst.get_patch_row_id(row_max); + int patch_col_id = patchInfoInst.get_patch_col_id(col_min); + for (int patch_row_id = patch_id_min; patch_row_id <= patch_id_max; ++patch_row_id) { + auto [split_node_id_min, split_node_id_max] = patchInfoInst.get_node_range(patch_row_id, false); + + if (patch_row_id == patch_id_min) { + split_node_id_min = row_min; + } + + if (patch_row_id == patch_id_max) { + split_node_id_max = row_max; + } + + int patch_id = patchInfoInst.patch_num_horizontal * patch_row_id + patch_col_id; + + auto* split_node_1 = node_grid.get_node(split_node_id_min, col_min); + auto* split_node_2 = node_grid.get_node(split_node_id_max, col_min); + if (split_node_1 == nullptr || split_node_2 == nullptr) { + LOG_ERROR << "Node error after split wire"; + } + node_map.emplace(patch_id, std::make_pair(split_node_1, split_node_2)); + } + } + } else { + /// via + } + + return node_map; +} + +void VecPatchInit::initLayoutPDN() +{ + auto& layout_layers = _layout->get_layout_layers(); + + for (auto& [patch_id, patch] : _patch_grid->get_patchs()) { + for (auto& [layer_id, patch_layer] : patch.get_layer_map()) { + auto* layout_layer = layout_layers.findLayoutLayer(layer_id); + if (nullptr == layout_layer) { + LOG_WARNING << "Can not get layer order : " << layer_id; + return; + } + auto& grid = layout_layer->get_grid(); + + for (int row = patch_layer.rowIdMin; row <= patch_layer.rowIdMax; ++row) { + for (int col = patch_layer.colIdMin; col <= patch_layer.colIdMax; ++col) { + } + } + } + } +} + +void VecPatchInit::initLayoutInstance() +{ +} + +void VecPatchInit::initLayoutIO() +{ +} + +void VecPatchInit::initLayoutNets() +{ +} + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/patch/data_manager/vec_patch_init.h b/src/vectorization/src/patch/data_manager/vec_patch_init.h new file mode 100644 index 0000000000000000000000000000000000000000..caebb6e59561880fea7d44fb72e806e624c215fb --- /dev/null +++ b/src/vectorization/src/patch/data_manager/vec_patch_init.h @@ -0,0 +1,51 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "vec_layout.h" +#include "vec_node.h" +#include "vec_patch.h" +#include "vec_patch_grid.h" + +namespace ivec { + +class VecPatchInit +{ + public: + VecPatchInit(VecLayout* layout, VecPatchGrid* patch_grid) : _layout(layout), _patch_grid(patch_grid) {} + ~VecPatchInit() {} + void init(); + + private: + VecLayout* _layout; + VecPatchGrid* _patch_grid; + + void init_patch_grid(); + + void initSubNet(); + void initSubNetFeature(); + + void initLayoutPDN(); + void initLayoutInstance(); + void initLayoutIO(); + void initLayoutNets(); + + std::map> splitWirePath(VecNode* node1, VecNode* node2); +}; + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/patch/database/CMakeLists.txt b/src/vectorization/src/patch/database/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..533a9f69b2ddc241b6ce4461168c9603c531a62b --- /dev/null +++ b/src/vectorization/src/patch/database/CMakeLists.txt @@ -0,0 +1,16 @@ +add_library(ivec_patch_db + vec_patch.cpp + vec_patch_grid.cpp +) + +target_link_libraries(ivec_patch_db + PUBLIC + log + ivec_db + ivec_util +) + +target_include_directories(ivec_patch_db + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/src/vectorization/src/patch/database/vec_patch.cpp b/src/vectorization/src/patch/database/vec_patch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ab96382ecb7c09d61736daa0247a9d6432c7c98 --- /dev/null +++ b/src/vectorization/src/patch/database/vec_patch.cpp @@ -0,0 +1,96 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "vec_patch.h" + +#include "vec_net.h" + +namespace ivec { +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void VecPatchLayer::addSubnet(int net_id, int64_t wire_id, VecNode* node1, VecNode* node2) +{ + auto* sub_net = findNet(net_id); + if (sub_net == nullptr) { + VecNet vec_net(net_id); + VecNetWire wire(nullptr, nullptr, wire_id); + wire.add_path(node1, node2); + vec_net.addWire(wire); + + _sub_nets.insert(std::make_pair(net_id, vec_net)); + } else { + auto* wire = sub_net->findWire(wire_id); + if (wire == nullptr) { + VecNetWire wire(nullptr, nullptr, wire_id); + wire.add_path(node1, node2); + sub_net->addWire(wire); + } else { + wire->add_path(node1, node2); + } + } +} + +void VecPatchLayer::addSubnet(VecNet* sub_net, int64_t wire_id, VecNode* node1, VecNode* node2) +{ + if (sub_net != nullptr) { + auto* wire = sub_net->findWire(wire_id); + if (wire == nullptr) { + VecNetWire wire(nullptr, nullptr, wire_id); + wire.add_path(node1, node2); + sub_net->addWire(wire); + } else { + wire->add_path(node1, node2); + } + } +} + +VecNet* VecPatchLayer::findNet(int net_id) +{ + auto it = _sub_nets.find(net_id); + if (it != _sub_nets.end()) { + return &it->second; + } + + return nullptr; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +VecPatchLayer* VecPatch::findLayer(int layer_id) +{ + auto it = _layer_map.find(layer_id); + if (it != _layer_map.end()) { + return &it->second; + } + + return nullptr; +} + +} // namespace ivec diff --git a/src/vectorization/src/patch/database/vec_patch.h b/src/vectorization/src/patch/database/vec_patch.h new file mode 100644 index 0000000000000000000000000000000000000000..28f95be50cef96d9fade248743f2c9577748e026 --- /dev/null +++ b/src/vectorization/src/patch/database/vec_patch.h @@ -0,0 +1,110 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include + +#include "vec_net.h" +#include "vec_node.h" + +namespace ivec { + +class VecPatchLayer +{ + public: + VecPatchLayer() {} + ~VecPatchLayer() {} + + // getter + std::map& get_sub_nets() { return _sub_nets; } + + // setter + + // operator + void addSubnet(int net_id, int64_t wire_id, VecNode* node1, VecNode* node2); + void addSubnet(VecNet* sub_net, int64_t wire_id, VecNode* node1, VecNode* node2); + VecNet* findNet(int net_id); + + public: + int layer_id = -1; + int rowIdMin = -1; + int rowIdMax = -1; + int colIdMin = -1; + int colIdMax = -1; + int wire_width = 0; + int wire_len = 0; + double wire_density = 0.0; + double congestion = 0.0; + + private: + std::map _sub_nets; /// int : net id +}; + +class VecPatch +{ + public: + VecPatch() {} + ~VecPatch() {} + + // getter + std::map& get_layer_map() { return _layer_map; } + + // setter + + // operator + VecPatchLayer* findLayer(int layer_id); + + public: + int patch_id = -1; + int patch_id_row = -1; + int patch_id_col = -1; + + int rowIdMin = -1; + int rowIdMax = -1; + int colIdMin = -1; + int colIdMax = -1; + + int area = 0; + double cell_density = -1; + int pin_density = -1; + double net_density = -1; + int macro_margin = 0; + double RUDY_congestion = -1; + double EGR_congestion = -1; + + // timing, power, IR Drop map + double timing_map = 0.0; + double power_map = 0.0; + double ir_drop_map = 0.0; + + private: + std::map _layer_map; /// int : layer id +}; + +} // namespace ivec diff --git a/src/vectorization/src/patch/database/vec_patch_grid.cpp b/src/vectorization/src/patch/database/vec_patch_grid.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cad675816e7dfc35b9990629a03e557b9d50ae83 --- /dev/null +++ b/src/vectorization/src/patch/database/vec_patch_grid.cpp @@ -0,0 +1,68 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "vec_patch_grid.h" + +#include "vec_grid_info.h" + +namespace ivec { +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +VecPatch* VecPatchGrid::findPatch(int node_row, int node_col) +{ + int patch_id = patchInfoInst.get_patch_id(node_row, node_col); + auto it = _patchs.find(patch_id); + if (it != _patchs.end()) { + return &it->second; + } + + return nullptr; +} + +VecPatch* VecPatchGrid::findPatch(int patch_id) +{ + auto it = _patchs.find(patch_id); + if (it != _patchs.end()) { + return &it->second; + } + + return nullptr; +} + +VecPatchLayer* VecPatchGrid::findPatchLayer(int patch_id, int layer_id) +{ + auto* patch = findPatch(patch_id); + if (patch != nullptr) { + return patch->findLayer(layer_id); + } + + return nullptr; +} + +} // namespace ivec diff --git a/src/vectorization/src/patch/database/vec_patch_grid.h b/src/vectorization/src/patch/database/vec_patch_grid.h new file mode 100644 index 0000000000000000000000000000000000000000..2fa2fe68a0a5183933ab84729134801e23cb6892 --- /dev/null +++ b/src/vectorization/src/patch/database/vec_patch_grid.h @@ -0,0 +1,61 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include + +#include "vec_patch.h" + +namespace ivec { + +class VecPatchGrid +{ + public: + VecPatchGrid() {} + ~VecPatchGrid() {} + + // getter + std::map& get_patchs() { return _patchs; } + std::map, std::pair>>& get_patch_xy_map() { return _patch_xy_map; } + + // setter + + // operator + VecPatch* findPatch(int node_row, int node_col); + VecPatch* findPatch(int patch_id); + + VecPatchLayer* findPatchLayer(int patch_id, int layer_id); + + public: + private: + std::map _patchs; /// int : patch id + std::map, std::pair>> _patch_xy_map; +}; + +} // namespace ivec diff --git a/src/vectorization/src/utility/CMakeLists.txt b/src/vectorization/src/utility/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a160eee20129d9e7ea44850e8bb02647dee21519 --- /dev/null +++ b/src/vectorization/src/utility/CMakeLists.txt @@ -0,0 +1,12 @@ +add_library(ivec_util + vec_grid_info.cpp +) + +target_link_libraries(ivec_util + PUBLIC +) + +target_include_directories(ivec_util + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) \ No newline at end of file diff --git a/src/vectorization/src/utility/vec_grid_info.cpp b/src/vectorization/src/utility/vec_grid_info.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b2488fbfa666312f3c50804ea1e009f969584d6c --- /dev/null +++ b/src/vectorization/src/utility/vec_grid_info.cpp @@ -0,0 +1,224 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include "vec_grid_info.h" + +namespace ivec { + +VecGridInfo* VecGridInfo::_info_inst = nullptr; +VecPatchInfo* VecPatchInfo::_info_inst = nullptr; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int64_t VecGridInfo::calculate_x(int64_t col) +{ + int64_t x = node_x_start + col * x_step; + return x > urx ? urx : x; +} + +int64_t VecGridInfo::calculate_y(int64_t row) +{ + int64_t y = node_y_start + row * y_step; + return y > ury ? ury : y; +} + +std::pair VecGridInfo::get_node_coodinate(int row_id, int col_id) +{ + int x = node_x_start + col_id * x_step; + int y = node_y_start + row_id * y_step; + + return std::make_pair(x, y); +} + +std::pair VecGridInfo::findNodeID(int x, int y) +{ + int row_id = findNodeID(y, true); + int col_id = findNodeID(x, false); + + return std::make_pair(row_id, col_id); +} + +int VecGridInfo::findNodeID(int value, bool b_row_id) +{ + int node_id = -1; + + auto node_start = b_row_id ? node_y_start : node_x_start; + auto step = b_row_id ? y_step : x_step; + auto node_num = b_row_id ? node_row_num : node_col_num; + + if (value <= node_start) { + node_id = 0; + } else { + auto remain = (value - node_start) % step; + auto index = (value - node_start) / step; + + node_id = index >= node_num ? node_num - 1 : index; + } + + return node_id; +} + +std::pair VecGridInfo::get_node_id_range(int coord1, int coord2, bool b_row_id) +{ + auto index_1 = findNodeID(coord1, b_row_id); + auto index_2 = findNodeID(coord2, b_row_id); + + return std::make_pair(index_1, index_2); +} + +std::tuple VecGridInfo::get_node_id_range(int x1, int x2, int y1, int y2) +{ + /// 0 : no direction + /// 1 : horizotal + /// 2 : vertival + int direction = (x2 - x1) == (y2 - y1) ? 0 : ((x2 - x1) > (y2 - y1) ? 1 : 2); + + /// row id + int row_id_1 = findNodeID(y1, true); + int row_id_2 = findNodeID(y2, true); + /// col id + int col_id_1 = findNodeID(x1, false); + int col_id_2 = findNodeID(x2, false); + + return std::tuple(std::min(row_id_1, row_id_2), std::max(row_id_1, row_id_2), std::min(col_id_1, col_id_2), + std::max(col_id_1, col_id_2)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +VecPatchInfo::VecPatchInfo() +{ + int core_row_start = gridInfoInst.y_start / gridInfoInst.y_step; + int core_col_start = gridInfoInst.x_start / gridInfoInst.x_step; + + patch_row_start = core_row_start % patch_row_step; + patch_col_start = core_col_start % patch_col_step; + + set_patch_num(); +} + +void VecPatchInfo::set_patch_num() +{ + { + patch_num_vertical = patch_row_start == 0 ? 0 : 1; + + int row_num = (gridInfoInst.node_row_num - patch_row_start) % patch_row_step == 0 + ? (gridInfoInst.node_row_num - patch_row_start) / patch_row_step + : (gridInfoInst.node_row_num - patch_row_start) / patch_row_step + 1; + + patch_num_vertical += row_num; + } + + { + patch_num_horizontal = patch_col_start == 0 ? 0 : 1; + + int right_num = (gridInfoInst.node_col_num - patch_col_start) % patch_col_step == 0 + ? (gridInfoInst.node_col_num - patch_col_start) / patch_col_step + : (gridInfoInst.node_col_num - patch_col_start) / patch_col_step + 1; + patch_num_horizontal += right_num; + } +} + +int VecPatchInfo::get_patch_id(int node_row, int node_col) +{ + return patch_num_horizontal * get_patch_row_id(node_row) + get_patch_col_id(node_col); +} + +int VecPatchInfo::get_patch_row_id(int node_row) +{ + int patch_row_id = 0; + if (node_row < patch_row_start) { + patch_row_id = 0; + } else { + patch_row_id = patch_row_start == 0 ? 0 : 1; + patch_row_id += ((node_row - patch_row_start) / patch_row_step); + } + + return patch_row_id; +} + +int VecPatchInfo::get_patch_col_id(int node_col) +{ + int patch_col_id = 0; + { + if (node_col < patch_col_start) { + patch_col_id = 0; + } else { + patch_col_id = patch_col_start == 0 ? 0 : 1; + patch_col_id += ((node_col - patch_col_start) / patch_col_step); + } + } + + return patch_col_id; +} + +std::pair VecPatchInfo::get_node_range(int index, bool b_horizontal) +{ + int min_id, max_id; + if (b_horizontal) { + if (patch_col_start == 0) { + min_id = index * patch_col_step; + max_id = (index + 1) * patch_col_step; + max_id = max_id > gridInfoInst.node_col_num ? gridInfoInst.node_col_num : max_id; + } else { + if (index == 0) { + min_id = 0; + max_id = patch_col_start; + } else if (index == patch_num_horizontal - 1) { + min_id = patch_col_start + (index - 1) * patch_col_step; + max_id = gridInfoInst.node_col_num; + } else { + min_id = patch_col_start + (index - 1) * patch_col_step; + max_id = patch_col_start + index * patch_col_step; + } + } + } else { + if (patch_row_start == 0) { + min_id = index * patch_row_step; + max_id = (index + 1) * patch_row_step; + max_id = max_id > gridInfoInst.node_row_num ? gridInfoInst.node_row_num : max_id; + } else { + if (index == 0) { + min_id = 0; + max_id = patch_row_start; + } else if (index == patch_num_vertical - 1) { + min_id = patch_row_start + (index - 1) * patch_row_step; + max_id = gridInfoInst.node_row_num; + } else { + min_id = patch_row_start + (index - 1) * patch_row_step; + max_id = patch_row_start + index * patch_row_step; + } + } + } + + return std::make_pair(min_id, max_id); +} + +} // namespace ivec diff --git a/src/vectorization/src/utility/vec_grid_info.h b/src/vectorization/src/utility/vec_grid_info.h new file mode 100644 index 0000000000000000000000000000000000000000..7816408920d9f2aea4df8af3f5e9433681499c92 --- /dev/null +++ b/src/vectorization/src/utility/vec_grid_info.h @@ -0,0 +1,155 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +/** + * @project vectorization + * @date 06/11/2024 + * @version 0.1 + * @description + * + */ + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include +#include +#include + +namespace ivec { + +#define gridInfoInst VecGridInfo::getInst() +#define patchInfoInst VecPatchInfo::getInst() + +class VecGridInfo +{ + public: + static VecGridInfo& getInst() + { + if (_info_inst == nullptr) { + _info_inst = new VecGridInfo(); + } + return *_info_inst; + } + + static void destroyInst(); + + // getter + std::pair get_node_id_range(int coord1, int coord2, bool b_row_id); + std::tuple get_node_id_range(int x1, int x2, int y1, int y2); + std::pair get_node_coodinate(int row_id, int col_id); + bool is_out_of_range(int row_id, int col_id) + { + return (row_id >= 0 && row_id < node_row_num) && (col_id >= 0 && col_id < node_col_num) ? false : true; + } + + // setter + + // operator + std::pair findNodeID(int x, int y); + int findNodeID(int value, bool b_row_id); + + int64_t calculate_x(int64_t col); + int64_t calculate_y(int64_t row); + + public: + int layer_order; + int llx; + int lly; + int urx; + int ury; + int x_start; + int node_x_start; + int x_step; + int y_start; + int node_y_start; + int y_step; + int node_row_num; /// node number on rows + int node_col_num; /// node number on cols + + private: + static VecGridInfo* _info_inst; + + VecGridInfo() {} + ~VecGridInfo() {} +}; + +class VecPatchInfo +{ + public: + static VecPatchInfo& getInst() + { + if (_info_inst == nullptr) { + _info_inst = new VecPatchInfo(); + } + return *_info_inst; + } + + static VecPatchInfo& getInst(int row_step, int col_step) + { + if (_info_inst == nullptr) { + _info_inst = new VecPatchInfo(row_step, col_step); + } else { + _info_inst->set_patch_size(row_step, col_step); + } + return *_info_inst; + } + + static void destroyInst(); + + /// getter + int get_patch_id(int node_row, int node_col); + int get_patch_row_id(int node_row); + int get_patch_col_id(int node_col); + std::pair get_node_range(int index, bool b_horizontal); + + // setter + void set_patch_size(int row_size, int col_size) + { + patch_row_step = row_size; + patch_col_step = col_size; + + set_patch_num(); + } + + // operator + + public: + int patch_row_start = 0; + int patch_row_step = 9 * 2 * 10; /// default 9T/180T + int patch_col_start = 0; + int patch_col_step = 9 * 2 * 10; /// default 9T/180T + int patch_num_vertical = 0; /// indicate how many patchs in vertical direciton + int patch_num_horizontal = 0; /// indicate how many patchs in horizontal direciton + + private: + static VecPatchInfo* _info_inst; + + VecPatchInfo(); + VecPatchInfo(int row_step, int col_step) : + patch_row_start(0), patch_row_step(row_step), + patch_col_start(0), patch_col_step(col_step), + patch_num_vertical(0), patch_num_horizontal(0) + { + set_patch_num(); + } + ~VecPatchInfo() {} + + void set_patch_num(); +}; + +} // namespace ivec diff --git a/src/vectorization/src/vectorization.cpp b/src/vectorization/src/vectorization.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b948d7320c8ca73284950b5ba6a0f637eba3f7a0 --- /dev/null +++ b/src/vectorization/src/vectorization.cpp @@ -0,0 +1,144 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** + +#include "vectorization.h" + +#include "Log.hh" +#include "MemoryMonitor.hh" +#include "idm.h" +#include "init_sta.hh" +#include "vec_feature.h" + +namespace ivec { +Vectorization::Vectorization() +{ + initLog(); +} + +void Vectorization::initLog(std::string log_path) +{ + char config[] = "vectorization"; + char* argv[] = {config}; + + if (log_path == "") { + log_path = dmInst->get_config().get_output_path() + "/log/"; + } + + ieda::Log::init(argv, log_path); +} + +bool Vectorization::buildLayoutData(const std::string path) +{ + bool b_success = _data_manager.buildLayoutData(); + + return b_success; +} + +bool Vectorization::buildGraphData(const std::string path) +{ + bool b_success = _data_manager.buildGraphData(); + + _data_manager.checkData(); + + _data_manager.saveData(path); + + return b_success; +} + +bool Vectorization::buildGraphDataWithoutSave(const std::string path) +{ + bool b_success = _data_manager.buildGraphData(); + return b_success; +} + +std::map Vectorization::getGraph(std::string path) +{ + return _data_manager.getGraph(path); +} + +void Vectorization::buildFeature(const std::string dir, int patch_row_step, int patch_col_step) +{ + { + /// build layout data + MemoryMonitor monitor("buildLayoutData", "./memory_usage.log"); + _data_manager.buildLayoutData(); + } + + { + /// build graph + MemoryMonitor monitor("buildGraphData", "./memory_usage.log"); + _data_manager.buildGraphData(); + } + + { + /// build patch data + MemoryMonitor monitor("buildPatchData", "./memory_usage.log"); + // buildPatchData(dir); + buildPatchData(dir, patch_row_step, patch_col_step); // default patch size + } + // build pattern + // _data_manager.buildPatternData(); + + /// check data + bool check_ok = _data_manager.checkData(); + + /// build feature + generateFeature(dir); + + /// save + _data_manager.saveData(dir); +} + +void Vectorization::generateFeature(const std::string dir) +{ + auto* patch_grid = _data_manager.patch_dm == nullptr ? nullptr : &_data_manager.patch_dm->get_patch_grid(); + VecFeature feature(&_data_manager.layout_dm.get_layout(), patch_grid, dir); + { + MemoryMonitor monitor("buildFeatureTiming", "./memory_usage.log"); + feature.buildFeatureTiming(); + } + { + MemoryMonitor monitor("buildFeatureDrc", "./memory_usage.log"); + feature.buildFeatureDrc(); + } + { + MemoryMonitor monitor("buildFeatureStatis", "./memory_usage.log"); + feature.buildFeatureStatis(); + } +} + +/// for run vectorization sta api. +bool Vectorization::runVecSTA(const std::string dir) +{ + auto* eval_tp = ieval::InitSTA::getInst(); // evaluate timing and power. + + eval_tp->runVecSTA(&_data_manager.layout_dm.get_layout(), dir); + + return true; +} + +bool Vectorization::buildPatchData(const std::string dir) +{ + return _data_manager.buildPatchData(dir); +} + +bool Vectorization::buildPatchData(const std::string dir, int patch_row_step, int patch_col_step) +{ + return _data_manager.buildPatchData(dir, patch_row_step, patch_col_step); +} + +} // namespace ivec \ No newline at end of file diff --git a/src/vectorization/src/vectorization.h b/src/vectorization/src/vectorization.h new file mode 100644 index 0000000000000000000000000000000000000000..efb93d7f31f5d52694adfcf4b360a2766b49b70e --- /dev/null +++ b/src/vectorization/src/vectorization.h @@ -0,0 +1,49 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once +#include + +#include "vec_dm.h" +#include "vec_net.h" + +namespace ivec { + +class Vectorization +{ + public: + Vectorization(); + ~Vectorization() {} + + bool buildLayoutData(const std::string path); + bool buildGraphData(const std::string path); + bool buildGraphDataWithoutSave(const std::string path); + std::map getGraph(std::string path); + void buildFeature(const std::string dir, int patch_row_step, int patch_col_step); + bool buildPatchData(const std::string dir); + bool buildPatchData(const std::string dir, int patch_row_step, int patch_col_step); + + bool runVecSTA(const std::string dir); + + private: + VecDataManager _data_manager; /// top module data manager + + void initLog(std::string log_path = ""); + + void generateFeature(const std::string dir); +}; + +} // namespace ivec \ No newline at end of file