diff --git a/CMakeLists.txt b/CMakeLists.txt index e040ae648..68ecf1725 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -Werror=return-type") set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -g -Wall -Werror=return-type") # set(CMAKE_BUILD_TYPE "Release") -set(BUILD_ECOS OFF) +set(BUILD_ECOS ON) set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb -Werror=return-type") # if(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "") diff --git a/scripts/design/ics55/config/rcx.json b/scripts/design/ics55/config/rcx.json index 78299d97f..66e01a2cf 100644 --- a/scripts/design/ics55/config/rcx.json +++ b/scripts/design/ics55/config/rcx.json @@ -5,43 +5,57 @@ "corners": [ { "name": "TYPICAL", - "temperature": 25, + "temperature": [25], "ecc_tf": "/corners/TYP.json", "itf_file": "/corners/TYP.itf", "captab_file": "/corners/TYP.captab", - "spef_file": "/RCX_ecc/output/gcd_TYPICAL.spef" + "spef_file": [ + { "25" : "/RCX_ecc/output/gcd_TYPICAL_25C.spef" } + ] }, { "name": "RCbest", - "temperature": 25, + "temperature": [-40, 125], "ecc_tf": "/corners/RCbest.json", "itf_file": "/corners/RCbest.itf", "captab_file": "/corners/RCbest.captab", - "spef_file": "/RCX_ecc/output/gcd_RCbest.spef" + "spef_file": [ + { "-40" : "/RCX_ecc/output/gcd_RCbest_m40C.spef" }, + { "125" : "/RCX_ecc/output/gcd_RCbest_125C.spef" } + ] }, { "name": "RCworst", - "temperature": 25, + "temperature": [-40, 125], "ecc_tf": "/corners/RCworst.json", "itf_file": "/corners/RCworst.itf", "captab_file": "/corners/RCworst.captab", - "spef_file": "/RCX_ecc/output/gcd_RCworst.spef" + "spef_file": [ + { "-40" : "/RCX_ecc/output/gcd_RCworst_m40C.spef" }, + { "125" : "/RCX_ecc/output/gcd_RCworst_125C.spef" } + ] }, { "name": "Cbest", - "temperature": 25, + "temperature": [-40, 125], "ecc_tf": "/corners/Cbest.json", "itf_file": "/corners/Cbest.itf", "captab_file": "/corners/Cbest.captab", - "spef_file": "/RCX_ecc/output/gcd_Cbest.spef" + "spef_file": [ + { "-40" : "/RCX_ecc/output/gcd_Cbest_m40C.spef" }, + { "125" : "/RCX_ecc/output/gcd_Cbest_125C.spef" } + ] }, { "name": "Cworst", - "temperature": 25, + "temperature": [-40, 125], "ecc_tf": "/corners/Cworst.json", "itf_file": "/corners/Cworst.itf", "captab_file": "/corners/Cworst.captab", - "spef_file": "/RCX_ecc/output/gcd_Cworst.spef" + "spef_file": [ + { "-40" : "/RCX_ecc/output/gcd_Cworst_m40C.spef" }, + { "125" : "/RCX_ecc/output/gcd_Cworst_125C.spef" } + ] } ] } \ No newline at end of file diff --git a/scripts/design/ics55/config/sta.json b/scripts/design/ics55/config/sta.json new file mode 100644 index 000000000..2a734ab07 --- /dev/null +++ b/scripts/design/ics55/config/sta.json @@ -0,0 +1,53 @@ +{ + "liberty" :[ + { + "corner": "MAX", + "temperature": 125, + "path" : [ + "/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CR/liberty/ics55_LLSC_H7CR_ss_rcworst_1p08_125_nldm.lib", + "/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CL/liberty/ics55_LLSC_H7CR_ss_rcworst_1p08_125_nldm.lib" + ] + }, + { + "corner": "WCL", + "temperature": -40, + "path" : [ + "/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CR/liberty/ics55_LLSC_H7CR_ss_cworst_1p08_m40_nldm.lib", + "/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CL/liberty/ics55_LLSC_H7CR_ss_cworst_1p08_m40_nldm.lib" + ] + }, + { + "corner": "TYP", + "temperature": 25, + "path" : [ + "/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CR/liberty/ics55_LLSC_H7CR_typ_tt_1p2_25_nldm.lib", + "/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CL/liberty/ics55_LLSC_H7CR_typ_tt_1p2_25_nldm.lib" + ] + }, + { + "corner": "MIN", + "temperature": -40, + "path" : [ + "/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CR/liberty/ics55_LLSC_H7CR_ff_rcbest_1p32_m40_nldm.lib", + "/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CL/liberty/ics55_LLSC_H7CR_ff_rcbest_1p32_m40_nldm.lib" + ] + }, + { + "corner": "ML", + "temperature": 125, + "path" : [ + "/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CR/liberty/ics55_LLSC_H7CR_ff_cbest_1p32_125_nldm.lib", + "/IP/STD_cell/ics55_LLSC_H7C_V1p10C100/ics55_LLSC_H7CL/liberty/ics55_LLSC_H7CR_ff_cbest_1p32_125_nldm.lib" + ] + } + ], + "signoff" : [ + { + "MAX": ["Cworst", "RCworst"], + "WCL": ["Cworst", "RCworst"], + "TYP": ["TYPICAL"], + "MIN": ["Cworst", "RCworst", "Cbest", "RCbest"], + "ML": ["Cworst", "RCworst", "Cbest", "RCbest"] + } + ] +} \ No newline at end of file diff --git a/scripts/design/ics55/readme.md b/scripts/design/ics55/readme.md index c9c60b78f..ab918e40b 100644 --- a/scripts/design/ics55/readme.md +++ b/scripts/design/ics55/readme.md @@ -1,6 +1,6 @@ # ICS55 ECC 脚本说明和用户手册 -本文档说明 `scripts/design/ics55` 目录下的 GCD 参考设计脚本、运行方式、输入输出目录和调试开关。该 flow 面向 ICS55 PDK,使用 `ecc_bin` 依次执行 floorplan、fanout 修复、place、CTS、legalization、route、DRC、filler、RCX 和 STA。 +本文档说明 `scripts/design/ics55` 目录下的 GCD 参考设计脚本、运行方式、输入输出目录和调试开关。该 flow 面向 ICS55 PDK,使用 `ecc_bin` 依次执行 floorplan、fanout 修复、place、CTS、legalization、route、DRC、filler、RCX、STA 和 harden。 ## 目录结构 @@ -22,10 +22,11 @@ scripts/design/ics55/ │ ├── CTS.tcl │ ├── legalization.tcl │ ├── route.tcl +│ ├── drc.tcl +│ ├── filler.tcl │ ├── rcx.tcl │ ├── sta.tcl -│ ├── drc.tcl -│ └── filler.tcl +│ └── harden.tcl └── gcd/ # 默认 workspace ├── home/ # workspace 元数据 ├── origin/ # workspace 输入 @@ -36,7 +37,7 @@ scripts/design/ics55/ └── _ecc/data/ # 工具工作目录 ``` -`_ecc` 包括 `Floorplan_ecc`、`fixFanout_ecc`、`place_ecc`、`CTS_ecc`、`legalization_ecc`、`route_ecc`、`RCX_ecc`、`sta_ecc`、`drc_ecc` 和 `filler_ecc`。 +`_ecc` 包括 `Floorplan_ecc`、`fixFanout_ecc`、`place_ecc`、`CTS_ecc`、`legalization_ecc`、`route_ecc`、`drc_ecc`、`filler_ecc`、`RCX_ecc`、`sta_ecc` 和 `harden_ecc`。 ## 前置条件 @@ -154,8 +155,9 @@ set RTL2GDS_FLOW 0 | 6 | route | `steps/route.tcl` | `legalization_ecc/output/gcd_legalization.def.gz` 或 `gcd_legalization_db` | `init_rt`、`run_rt` | `route_ecc/output/gcd_route.*`、`gcd_route_db` | | 7 | drc | `steps/drc.tcl` | `route_ecc/output/gcd_route.def.gz` 或 `gcd_route_db` | `init_drc`、`run_drc` | `drc_ecc/output/gcd_drc.*`、`gcd_drc_db`、`report/drc.rpt` | | 8 | filler | `steps/filler.tcl` | `drc_ecc/output/gcd_drc.def.gz` 或 `gcd_drc_db` | `run_filler` | `filler_ecc/output/gcd_filler.*`、`gcd_filler_db` | -| 9 | RCX | `steps/rcx.tcl` | `filler_ecc/output/gcd_filler.def.gz` 或 `gcd_filler_db`、`config/rcx.json` | `init_rcx`、`read_mapping`、`read_corner`、`run_rcx`、`report_rcx` | `RCX_ecc/output/gcd_RCX.*`、`gcd_RCX_db`、`gcd_.spef` | -| 10 | sta | `steps/sta.tcl` | `RCX_ecc/output/gcd_RCX.v`、`origin/gcd.sdc`、`config/rcx.json` 中的 SPEF | `read_netlist`、`read_liberty`、`read_sdc`、`read_spef`、`report_timing` | `sta_ecc/output/gcd_sta.*`、`output/sta//` | +| 9 | RCX | `steps/rcx.tcl` | `filler_ecc/output/gcd_filler.def.gz` 或 `gcd_filler_db`、`config/rcx.json` | `init_rcx -config`、`run_rcx`、`report_rcx` | `RCX_ecc/output/gcd_RCX.*`、`gcd_RCX_db`、`gcd_.spef` | +| 10 | sta | `steps/sta.tcl` | `filler_ecc/output/gcd_filler.def.gz` 或 `gcd_filler_db`、`origin/gcd.sdc`、`config/rcx.json` 中的 SPEF | `read_netlist`、`read_liberty`、`read_sdc`、`read_spef`、`report_timing` | `sta_ecc/output/gcd_sta.*`、`output/sta//` | +| 11 | harden | `steps/harden.tcl` | `filler_ecc/output/gcd_filler.def.gz` 或 `gcd_filler_db` | `gds_save -harden`、`write_soc_json`、`write_abstract_lef`、`write_timing_model` | `harden_ecc/output/gcd_harden.gds`、`gcd_harden.json`、`gcd_harden.lef`、`gcd_harden.lib`、`gcd_harden_db` | 每个 step 的 `output` 目录通常包含: @@ -163,7 +165,7 @@ set RTL2GDS_FLOW 0 - `*.v`:保存后的 Verilog netlist - `*.gds`:保存后的 GDS,失败时脚本只打印 warning 并继续 - `*_db/`:`save_data` 保存的持久化 idb 数据 -- `*.json`:脚本中预留的 `json_save` 路径,当前 `step_common.tcl` 中 `json_save` 被注释,默认不会生成 +- `*.json`:脚本中预留的 `json_save` 路径,当前 `step_common.tcl` 中 `json_save` 被注释,普通 step 默认不会生成;`harden` step 会通过 `write_soc_json` 生成 SoC harden JSON 每个 step 的 `report` 目录通常包含: @@ -215,7 +217,7 @@ gcd/config/_default_config.json `step_common.tcl` 中的 `step_prepare_configs` 会把配置里的相对目录展开为绝对路径: -- `Floorplan_ecc`、`fixFanout_ecc`、`place_ecc`、`CTS_ecc`、`legalization_ecc`、`route_ecc`、`RCX_ecc`、`sta_ecc`、`drc_ecc`、`filler_ecc`、`config`、`origin`、`home` 展开到 workspace 根目录。 +- `Floorplan_ecc`、`fixFanout_ecc`、`place_ecc`、`CTS_ecc`、`legalization_ecc`、`route_ecc`、`drc_ecc`、`filler_ecc`、`RCX_ecc`、`sta_ecc`、`harden_ecc`、`config`、`origin`、`home` 展开到 workspace 根目录。 - `IP`、`prtech`、`corners` 展开到 PDK 根目录。 因此运行脚本后,`gcd/config/*.json` 可能会被改写成绝对路径,这是预期行为。`steps/rtl2gds.tcl` 会先 source `create_workspace.tcl`,重新创建默认 `gcd` workspace 并复制 `config/`、`origin/` 模板;单步 `run_ecc.sh` 不会自动重建 workspace。 @@ -249,7 +251,7 @@ gcd/config/_default_config.json 支持的 step: ```text -Floorplan fixFanout place CTS legalization route drc filler RCX sta +Floorplan fixFanout place CTS legalization route drc filler RCX sta harden ``` ## 常见问题 diff --git a/scripts/design/ics55/run_ecc.sh b/scripts/design/ics55/run_ecc.sh index bdb60367a..61bdfe60f 100755 --- a/scripts/design/ics55/run_ecc.sh +++ b/scripts/design/ics55/run_ecc.sh @@ -6,7 +6,7 @@ REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" ECC_BINARY="${ECC_BINARY:-${REPO_ROOT}/bin/ecc_bin}" WORKSPACE="${WORKSPACE_HOME:-gcd}" -STEPS=(Floorplan fixFanout place CTS legalization route drc filler RCX sta) +STEPS=(create_workspace Floorplan fixFanout place CTS legalization route drc filler RCX sta harden) usage() { cat < "${runner}" < save harden data" +step_print_path "output_def" $output_def +step_print_path "output_verilog" $output_verilog +step_print_path "output_gds" $output_gds +step_print_path "output_json" $output_json +step_print_path "output_lef" $output_lef +step_print_path "output_lib" $output_lib +step_print_path "output_db" $output_db +step_print_path "feature_db" $feature_db +step_print_path "feature_step" $feature_step +step_print_path "report_db" $report_db +step_print_path "sta_dir" $sta_dir + +step_ensure_parent_dir $output_def +step_ensure_parent_dir $output_verilog +step_ensure_parent_dir $output_gds +step_ensure_parent_dir $output_json +step_ensure_parent_dir $output_lef +step_ensure_parent_dir $output_lib +step_ensure_parent_dir $output_db +step_ensure_parent_dir $feature_db +step_ensure_parent_dir $feature_step +step_ensure_parent_dir $report_db +file mkdir $sta_dir + +def_save -path $output_def +netlist_save -path $output_verilog -exclude_cell_names {} +gds_save -path $output_gds -harden +write_abstract_lef -path $output_lef + +set timing_status [catch { + release_sta + init_sta $sta_dir + update_timing + write_timing_model -output_lib_path $output_lib -analysis_mode max +} timing_err timing_opts] +step_safe_eval {release_sta} +if {$timing_status != 0} { + error $timing_err +} + +save_data -path $output_db + +set validate_path [file join [file dirname $report_db] "${step_name}.idb_validate.json"] +if {[llength [info commands idb_validate]] > 0} { + step_safe_eval [list idb_validate -path $validate_path] +} +feature_summary -path $feature_db +# feature_tool does not currently have a harden step parser. +report_db -path $report_db + +if {$RTL2GDS == 0} { + puts "RTL2GDS is disabled, exiting flow." + step_maybe_flow_exit +} diff --git a/scripts/design/ics55/steps/rcx.tcl b/scripts/design/ics55/steps/rcx.tcl index 541ede551..126b6c186 100644 --- a/scripts/design/ics55/steps/rcx.tcl +++ b/scripts/design/ics55/steps/rcx.tcl @@ -68,29 +68,13 @@ if {$RTL2GDS == 0} { step_restore_or_load_design $flow_config $db_config $output_dir $tech_lef $lef_files $input_def $input_verilog $top_module $input_db } -step_require_file "rcx mapping file" $rcx_mapping_file -if {[llength $rcx_corners] <= 0} { - error "no RCX corners found in $rcx_config" -} - -file mkdir $rcx_output_dir -init_rcx -thread $rcx_thread_num -read_mapping $rcx_mapping_file - -foreach corner $rcx_corners { - set corner_name [step_dict_get_default $corner name ""] - set itf_file [step_dict_get_default $corner itf_file ""] - set captab_file [step_dict_get_default $corner captab_file ""] - if {$corner_name eq ""} { - error "RCX corner has no name in $rcx_config" - } - step_require_file "RCX ITF for $corner_name" $itf_file - step_require_file "RCX captab for $corner_name" $captab_file - read_corner -name $corner_name -itf $itf_file -captab $captab_file +if {$rcx_output_dir ne ""} { + file mkdir $rcx_output_dir } +init_rcx -config $rcx_config run_rcx -report_rcx $rcx_output_dir +report_rcx step_save_design $step_name $output_def $output_verilog $output_gds $output_json $output_db $feature_db $feature_step $report_db $sta_dir 0 diff --git a/scripts/design/ics55/steps/rtl2gds.tcl b/scripts/design/ics55/steps/rtl2gds.tcl index d9b9a9dc2..9e0c8f8c0 100644 --- a/scripts/design/ics55/steps/rtl2gds.tcl +++ b/scripts/design/ics55/steps/rtl2gds.tcl @@ -19,8 +19,9 @@ source $script_dir/legalization.tcl source $script_dir/route.tcl source $script_dir/drc.tcl source $script_dir/filler.tcl -# source $script_dir/rcx.tcl -# source $script_dir/sta.tcl +source $script_dir/rcx.tcl +source $script_dir/sta.tcl +source $script_dir/harden.tcl set RTL2GDS_FLOW 0 step_maybe_flow_exit diff --git a/scripts/design/ics55/steps/sta.tcl b/scripts/design/ics55/steps/sta.tcl index 3f52d0d45..11125e24e 100644 --- a/scripts/design/ics55/steps/sta.tcl +++ b/scripts/design/ics55/steps/sta.tcl @@ -12,6 +12,325 @@ set step_name "sta" set script_dir [file normalize [file dirname [info script]]] source [file normalize [file join $script_dir step_common.tcl]] +proc sta_json_parse {text} { + set index 0 + set length [string length $text] + set value [sta_json_parse_value $text index $length] + sta_json_skip_space $text index $length + if {$index < $length} { + error "unexpected JSON data near index $index" + } + return $value +} + +proc sta_json_skip_space {text index_var length} { + upvar 1 $index_var index + while {$index < $length} { + set char [string index $text $index] + if {$char ne " " && $char ne "\n" && $char ne "\r" && $char ne "\t"} { + break + } + incr index + } +} + +proc sta_json_parse_value {text index_var length} { + upvar 1 $index_var index + sta_json_skip_space $text index $length + if {$index >= $length} { + error "unexpected end of JSON data" + } + + set char [string index $text $index] + switch -- $char { + "\{" { + return [sta_json_parse_object $text index $length] + } + "\[" { + return [sta_json_parse_array $text index $length] + } + "\"" { + return [sta_json_parse_string $text index $length] + } + default { + return [sta_json_parse_scalar $text index $length] + } + } +} + +proc sta_json_parse_object {text index_var length} { + upvar 1 $index_var index + incr index + set result [dict create] + sta_json_skip_space $text index $length + if {[string index $text $index] eq "\}"} { + incr index + return $result + } + + while {$index < $length} { + sta_json_skip_space $text index $length + if {[string index $text $index] ne "\""} { + error "expected JSON object key near index $index" + } + set key [sta_json_parse_string $text index $length] + sta_json_skip_space $text index $length + if {[string index $text $index] ne ":"} { + error "expected ':' after JSON object key '$key' near index $index" + } + incr index + set value [sta_json_parse_value $text index $length] + dict set result $key $value + + sta_json_skip_space $text index $length + set char [string index $text $index] + if {$char eq "\}"} { + incr index + return $result + } + if {$char ne ","} { + error "expected comma or object close in JSON object near index $index" + } + incr index + } + + error "unterminated JSON object" +} + +proc sta_json_parse_array {text index_var length} { + upvar 1 $index_var index + incr index + set result {} + sta_json_skip_space $text index $length + if {[string index $text $index] eq "\]"} { + incr index + return $result + } + + while {$index < $length} { + lappend result [sta_json_parse_value $text index $length] + sta_json_skip_space $text index $length + set char [string index $text $index] + if {$char eq "\]"} { + incr index + return $result + } + if {$char ne ","} { + error "expected ',' or ']' in JSON array near index $index" + } + incr index + } + + error "unterminated JSON array" +} + +proc sta_json_parse_string {text index_var length} { + upvar 1 $index_var index + incr index + set result "" + + while {$index < $length} { + set char [string index $text $index] + if {$char eq "\""} { + incr index + return $result + } + + if {$char eq "\\"} { + incr index + if {$index >= $length} { + error "unterminated JSON string escape" + } + set escape [string index $text $index] + switch -- $escape { + "\"" {append result "\""} + "\\" {append result "\\"} + "/" {append result "/"} + "b" {append result "\b"} + "f" {append result "\f"} + "n" {append result "\n"} + "r" {append result "\r"} + "t" {append result "\t"} + "u" { + set code [string range $text [expr {$index + 1}] [expr {$index + 4}]] + if {![regexp {^[0-9A-Fa-f]{4}$} $code]} { + error "invalid JSON unicode escape near index $index" + } + append result [format %c [scan $code %x]] + incr index 4 + } + default { + error "invalid JSON escape '\\$escape' near index $index" + } + } + } else { + append result $char + } + incr index + } + + error "unterminated JSON string" +} + +proc sta_json_parse_scalar {text index_var length} { + upvar 1 $index_var index + set start $index + while {$index < $length} { + set char [string index $text $index] + if {$char eq "," || $char eq "\]" || $char eq "\}" || $char eq " " || $char eq "\n" || $char eq "\r" || $char eq "\t"} { + break + } + incr index + } + + set value [string range $text $start [expr {$index - 1}]] + if {$value eq ""} { + error "expected JSON value near index $index" + } + if {$value in {true false null}} { + return $value + } + if {[regexp {^-?[0-9]+([.][0-9]+)?([eE][+-]?[0-9]+)?$} $value]} { + return $value + } + error "invalid JSON scalar '$value' near index $start" +} + +proc sta_load_json {path} { + step_require_file "JSON config" $path + return [sta_json_parse [step_read_text_file $path]] +} + +proc sta_resolve_path {path workspace_root pdk_root} { + set expanded [step_expand_config_text "\"$path\"" $workspace_root $pdk_root] + if {[string length $expanded] >= 2 && [string index $expanded 0] eq "\"" && [string index $expanded end] eq "\""} { + return [string range $expanded 1 end-1] + } + return $expanded +} + +proc sta_temp_dir_token {temperature} { + set token [string map {- m} $temperature] + return [step_safe_dir_name $token] +} + +proc sta_find_liberty_corner {sta_data corner_name} { + if {![dict exists $sta_data liberty]} { + error "sta config missing liberty list" + } + foreach liberty [dict get $sta_data liberty] { + if {[dict get $liberty corner] eq $corner_name} { + return $liberty + } + } + error "no liberty corner '$corner_name' found in sta config" +} + +proc sta_find_rcx_corner {rcx_data rcx_corner_name} { + if {![dict exists $rcx_data corners]} { + error "rcx config missing corners list" + } + foreach corner [dict get $rcx_data corners] { + if {[dict get $corner name] eq $rcx_corner_name} { + return $corner + } + } + error "no rcx corner '$rcx_corner_name' found in rcx config" +} + +proc sta_find_spef_for_temp {rcx_corner temperature} { + if {![dict exists $rcx_corner spef_file]} { + error "rcx corner '[dict get $rcx_corner name]' missing spef_file list" + } + foreach spef_item [dict get $rcx_corner spef_file] { + if {[dict exists $spef_item $temperature]} { + return [dict get $spef_item $temperature] + } + } + error "no SPEF for rcx corner '[dict get $rcx_corner name]' at temperature $temperature" +} + +proc sta_normalize_spef_path {spef_file} { + if {$spef_file eq "" || [file exists $spef_file]} { + return $spef_file + } + + set dirname [file dirname $spef_file] + set tail [file tail $spef_file] + if {[regexp {^(.*_)M([0-9]+C[.]spef)$} $tail -> prefix suffix]} { + set normalized [file join $dirname "${prefix}m${suffix}"] + if {[file exists $normalized]} { + return $normalized + } + } + + return $spef_file +} + +proc sta_normalize_liberty_path {liberty_file} { + if {$liberty_file eq "" || [file exists $liberty_file]} { + return $liberty_file + } + + set liberty_dir [file dirname $liberty_file] + set cell_dir [file tail [file dirname $liberty_dir]] + set tail [file tail $liberty_file] + if {[regexp {^(ics55_LLSC_H7C[[:alnum:]]+)(_.+)$} $tail -> old_prefix suffix]} { + set normalized [file join $liberty_dir "${cell_dir}${suffix}"] + if {[file exists $normalized]} { + return $normalized + } + } + + return $liberty_file +} + +proc sta_collect_signoff_items {sta_config rcx_config workspace_root pdk_root} { + set sta_data [sta_load_json $sta_config] + set rcx_data [sta_load_json $rcx_config] + + if {![dict exists $sta_data signoff]} { + error "sta config missing signoff list" + } + + set items {} + foreach signoff_group [dict get $sta_data signoff] { + foreach {corner_name rcx_corner_names} $signoff_group { + set liberty [sta_find_liberty_corner $sta_data $corner_name] + set temperature [dict get $liberty temperature] + set liberty_files {} + foreach liberty_file [dict get $liberty path] { + set liberty_file [sta_resolve_path $liberty_file $workspace_root $pdk_root] + lappend liberty_files [sta_normalize_liberty_path $liberty_file] + } + + foreach rcx_corner_name $rcx_corner_names { + set rcx_corner [sta_find_rcx_corner $rcx_data $rcx_corner_name] + set spef_file [sta_find_spef_for_temp $rcx_corner $temperature] + set spef_file [sta_resolve_path $spef_file $workspace_root $pdk_root] + set spef_file [sta_normalize_spef_path $spef_file] + lappend items [dict create \ + corner $corner_name \ + temperature $temperature \ + rcx_corner $rcx_corner_name \ + liberty_files $liberty_files \ + spef_file $spef_file] + } + } + } + + return $items +} + +proc sta_apply_data_config {db_config output_dir liberty_files sdc_file spef_file} { + db_init \ + -config $db_config \ + -output_dir_path $output_dir \ + -lib_path $liberty_files \ + -sdc_path $sdc_file \ + -spef_path $spef_file +} + set flow_dir [file normalize [file join $script_dir ..]] set default_workspace [file normalize [file join $flow_dir gcd home]] set default_pdk [file normalize [file join $flow_dir .. .. .. .. icsprout55-pdk]] @@ -28,12 +347,13 @@ source [file normalize [file join $script_dir pdk.tcl]] set flow_config [file join $config_dir flow_config.json] set db_config [file join $config_dir db_default_config.json] set rcx_config [file join $config_dir rcx.json] +set sta_config [file join $config_dir sta.json] set output_dir [file join $step_dir output] -set rcx_output_dir [file join $workspace_root RCX_ecc output] -set input_def [file join $rcx_output_dir gcd_RCX.def.gz] -set input_verilog [file join $rcx_output_dir gcd_RCX.v] -set input_db [file join $rcx_output_dir gcd_RCX_db] +set filler_output_dir [file join $workspace_root filler_ecc output] +set input_def [file join $filler_output_dir gcd_filler.def.gz] +set input_verilog [file join $filler_output_dir gcd_filler.v] +set input_db [file join $filler_output_dir gcd_filler_db] set output_def [file join $output_dir gcd_sta.def.gz] set output_verilog [file join $output_dir gcd_sta.v] @@ -44,54 +364,58 @@ set feature_db [file join $step_dir feature sta.db.json] set feature_step [file join $step_dir feature sta.step.json] set report_db [file join $step_dir report sta.db.rpt] set sta_dir [file join $step_dir data sta] -set sta_report_root [file join $output_dir sta] +set sta_report_root $output_dir step_update_flow_config $flow_config $config_dir step_update_db_config $db_config $input_def $input_verilog $output_dir -step_prepare_configs [list $flow_config $db_config $rcx_config] $workspace_root $pdk_root -set spef_items [step_collect_spef_items $rcx_config $design_name {}] +step_prepare_configs [list $flow_config $db_config $rcx_config $sta_config] $workspace_root $pdk_root +set signoff_items [sta_collect_signoff_items $sta_config $rcx_config $workspace_root $pdk_root] puts "==============================" puts "Running $step_name" puts "Workspace: $workspace_root" puts "PDK: $pdk_root" +step_print_path "sta_config" $sta_config step_print_path "rcx_config" $rcx_config step_print_path "input_verilog" $input_verilog step_print_path "sdc_file" $sdc_file -step_print_list "lib_files" $lib_files if {$RTL2GDS == 0} { puts "RTL2GDS is disabled, loading data." step_restore_or_load_design $flow_config $db_config $output_dir $tech_lef $lef_files $input_def $input_verilog $top_module $input_db } -if {[llength $spef_items] <= 0} { - error "no SPEF files found for STA in $rcx_config" +if {[llength $signoff_items] <= 0} { + error "no signoff STA items found in $sta_config" } -step_require_file "STA netlist" $input_verilog -step_require_files "STA liberty" $lib_files step_require_file "STA SDC" $sdc_file file mkdir $sta_report_root -foreach spef_item $spef_items { - lassign $spef_item spef_type spef_file - step_require_file "STA SPEF for $spef_type" $spef_file +foreach signoff_item $signoff_items { + set corner_name [dict get $signoff_item corner] + set temperature [dict get $signoff_item temperature] + set rcx_corner_name [dict get $signoff_item rcx_corner] + set signoff_lib_files [dict get $signoff_item liberty_files] + set signoff_spef_file [dict get $signoff_item spef_file] + set report_corner_dir "${corner_name}_[sta_temp_dir_token $temperature]" + set report_dir [file join $sta_report_root $report_corner_dir [step_safe_dir_name $rcx_corner_name]] - set report_dir [file join $sta_report_root $spef_type] + step_require_files "STA liberty for $corner_name" $signoff_lib_files + step_require_file "STA SPEF for $corner_name/$rcx_corner_name at $temperature" $signoff_spef_file file mkdir $report_dir - puts "==> run STA for $spef_type" - step_print_path "spef_file" $spef_file + puts "==> run STA for $corner_name/$rcx_corner_name at ${temperature}C" + step_print_list "lib_files" $signoff_lib_files + step_print_path "spef_file" $signoff_spef_file step_print_path "report_dir" $report_dir set sta_status [catch { - set_design_workspace $report_dir - read_netlist $input_verilog - read_liberty $lib_files - link_design $top_module - read_sdc $sdc_file - read_spef $spef_file + sta_apply_data_config $db_config $output_dir $signoff_lib_files $sdc_file $signoff_spef_file + release_sta + init_sta $report_dir + read_spef $signoff_spef_file report_timing + release_sta } sta_err sta_opts] step_safe_eval {release_sta} if {$sta_status != 0} { diff --git a/scripts/design/ics55/steps/step_common.tcl b/scripts/design/ics55/steps/step_common.tcl index 6845a6e23..ae99b973e 100644 --- a/scripts/design/ics55/steps/step_common.tcl +++ b/scripts/design/ics55/steps/step_common.tcl @@ -93,7 +93,7 @@ proc step_expand_config_text {text workspace_root pdk_root} { set replacements {} foreach prefix { CTS_ecc Floorplan_ecc fixFanout_ecc place_ecc legalization_ecc - route_ecc drc_ecc filler_ecc RCX_ecc rcx_ecc sta_ecc config origin home + route_ecc drc_ecc filler_ecc RCX_ecc rcx_ecc sta_ecc harden_ecc config origin home } { lappend replacements "\"/$prefix\"" "\"$workspace_root/$prefix\"" lappend replacements "\"/$prefix/" "\"$workspace_root/$prefix/" diff --git a/src/interface/tcl/tcl_idb/tcl_db_file.cpp b/src/interface/tcl/tcl_idb/tcl_db_file.cpp index 2c87486eb..7f6558c7f 100644 --- a/src/interface/tcl/tcl_idb/tcl_db_file.cpp +++ b/src/interface/tcl/tcl_idb/tcl_db_file.cpp @@ -503,6 +503,39 @@ unsigned CmdWriteSocJson::exec() return soc_file.saveFileData() ? 1 : 0; } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CmdWriteAbstractLef::CmdWriteAbstractLef(const char* cmd_name) : TclCmd(cmd_name) +{ + auto* path = new TclStringOption(TCL_PATH, 1); + addOption(path); +} + +unsigned CmdWriteAbstractLef::check() +{ + TclOption* path = getOptionOrArg(TCL_PATH); + LOG_FATAL_IF(!path); + + return 1; +} + +unsigned CmdWriteAbstractLef::exec() +{ + if (!check()) { + return 0; + } + + TclOption* path = getOptionOrArg(TCL_PATH); + auto* str_path = path->getStringVal(); + if (str_path == nullptr) { + return 0; + } + + dmInst->saveLef(str_path); + return 1; +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/interface/tcl/tcl_idb/tcl_db_file.h b/src/interface/tcl/tcl_idb/tcl_db_file.h index ba0d679ff..c2b542a48 100644 --- a/src/interface/tcl/tcl_idb/tcl_db_file.h +++ b/src/interface/tcl/tcl_idb/tcl_db_file.h @@ -262,4 +262,18 @@ class CmdWriteSocJson : public TclCmd // private data }; +class CmdWriteAbstractLef : public TclCmd +{ + public: + explicit CmdWriteAbstractLef(const char* cmd_name); + ~CmdWriteAbstractLef() override = default; + + unsigned check() override; + unsigned exec() override; + + private: + // private function + // private data +}; + } // namespace tcl diff --git a/src/interface/tcl/tcl_idb/tcl_register_idb.h b/src/interface/tcl/tcl_idb/tcl_register_idb.h index 7802438da..a37bae276 100644 --- a/src/interface/tcl/tcl_idb/tcl_register_idb.h +++ b/src/interface/tcl/tcl_idb/tcl_register_idb.h @@ -49,6 +49,7 @@ int registerCmdDB() registerTclCmd(CmdLoadData, "load_data"); registerTclCmd(CmdValidateIdb, "idb_validate"); registerTclCmd(CmdWriteSocJson, "write_soc_json"); + registerTclCmd(CmdWriteAbstractLef, "write_abstract_lef"); registerTclCmd(CmdSaveGDS, "gds_save"); registerTclCmd(CmdGenerateMPScript, "aimp_random"); diff --git a/src/platform/file_manager/db_fm/file_soc.cpp b/src/platform/file_manager/db_fm/file_soc.cpp index 3cd2f8046..ba4120b93 100644 --- a/src/platform/file_manager/db_fm/file_soc.cpp +++ b/src/platform/file_manager/db_fm/file_soc.cpp @@ -31,6 +31,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "file_soc.h" +#include #include #include #include @@ -166,7 +167,31 @@ bool JsonSoc::saveJson() json core_list_json = json::array(); auto* instance_list = idb_design == nullptr ? nullptr : idb_design->get_instance_list(); int num_cores = 0; - for(auto inst : instance_list->get_instance_list()) { + std::vector sorted_instances = instance_list == nullptr ? std::vector() : instance_list->get_instance_list(); + std::stable_sort(sorted_instances.begin(), sorted_instances.end(), [](IdbInstance* left, IdbInstance* right) { + if (left == nullptr) { + return false; + } + if (right == nullptr) { + return true; + } + + auto* left_box = left->get_bounding_box(); + auto* right_box = right->get_bounding_box(); + if (left_box == nullptr) { + return false; + } + if (right_box == nullptr) { + return true; + } + + if (left_box->get_high_y() != right_box->get_high_y()) { + return left_box->get_high_y() > right_box->get_high_y(); + } + return left_box->get_low_x() < right_box->get_low_x(); + }); + + for (auto inst : sorted_instances) { if(inst == nullptr || inst->get_cell_master() == nullptr || !is_exist_harden_core(inst->get_name())) { continue; } diff --git a/src/platform/file_manager/db_fm/file_soc.h b/src/platform/file_manager/db_fm/file_soc.h index e5dc517a1..fb47822ba 100644 --- a/src/platform/file_manager/db_fm/file_soc.h +++ b/src/platform/file_manager/db_fm/file_soc.h @@ -16,6 +16,7 @@ // *************************************************************************************** #pragma once +#include //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////