diff --git a/include/ord/OpenRoad.hh b/include/ord/OpenRoad.hh index c4d0817c2c4..62ecb50221c 100644 --- a/include/ord/OpenRoad.hh +++ b/include/ord/OpenRoad.hh @@ -227,6 +227,7 @@ class OpenRoad void write3Dbv(const std::string& filename); void write3Dbx(const std::string& filename); void read3DBloxBMap(const std::string& filename); + void check3DBlox(); void readDb(std::istream& stream); void readDb(const char* filename, bool hierarchy = false); diff --git a/src/OpenRoad.cc b/src/OpenRoad.cc index 3db37af8b66..0a9b57c4ba4 100644 --- a/src/OpenRoad.cc +++ b/src/OpenRoad.cc @@ -493,7 +493,7 @@ void OpenRoad::read3Dbx(const std::string& filename) { odb::ThreeDBlox parser(logger_, db_, sta_); parser.readDbx(filename); - parser.check(); + check3DBlox(); db_->triggerPostRead3Dbx(db_->getChip()); } @@ -503,6 +503,16 @@ void OpenRoad::read3DBloxBMap(const std::string& filename) parser.readBMap(filename); } +void OpenRoad::check3DBlox() +{ + if (db_->getChip() == nullptr) { + logger_->error(utl::ORD, 76, "No design loaded."); + return; + } + odb::ThreeDBlox checker(logger_, db_, sta_); + checker.check(); +} + void OpenRoad::write3Dbv(const std::string& filename) { odb::ThreeDBlox writer(logger_, db_, sta_); diff --git a/src/OpenRoad.i b/src/OpenRoad.i index df619b86e54..5742d6e6800 100644 --- a/src/OpenRoad.i +++ b/src/OpenRoad.i @@ -376,6 +376,13 @@ read_3dblox_bmap_cmd(const char *filename) ord->read3DBloxBMap(filename); } +void +check_3dblox_cmd() +{ + OpenRoad *ord = getOpenRoad(); + ord->check3DBlox(); +} + void write_3dbv_cmd(const char *filename) { diff --git a/src/OpenRoad.tcl b/src/OpenRoad.tcl index d7910a4707c..205d07ab125 100644 --- a/src/OpenRoad.tcl +++ b/src/OpenRoad.tcl @@ -228,6 +228,14 @@ proc read_3dblox_bmap { args } { ord::read_3dblox_bmap_cmd $filename } +sta::define_cmd_args "check_3dblox" {} + +proc check_3dblox { args } { + sta::parse_key_args "check_3dblox" args keys {} flags {} + sta::check_argc_eq0 "check_3dblox" $args + ord::check_3dblox_cmd +} + sta::define_cmd_args "write_db" {filename} sta::define_cmd_args "read_db" {[-hier] filename} diff --git a/src/odb/test/BUILD b/src/odb/test/BUILD index 30ae25f4bc4..d1ff827cd8f 100644 --- a/src/odb/test/BUILD +++ b/src/odb/test/BUILD @@ -145,6 +145,7 @@ COMPULSORY_TESTS = [ "all_pins_placed1", "all_pins_placed2", "bterm_hier_create", + "check_3dblox", "check_routing_tracks", "create_blockage", "create_obstruction", diff --git a/src/odb/test/CMakeLists.txt b/src/odb/test/CMakeLists.txt index 4736460d9c2..f720fc41043 100644 --- a/src/odb/test/CMakeLists.txt +++ b/src/odb/test/CMakeLists.txt @@ -5,6 +5,7 @@ or_integration_tests( all_pins_placed1 all_pins_placed2 bterm_hier_create + check_3dblox check_routing_tracks create_blockage create_obstruction diff --git a/src/odb/test/check_3dblox.ok b/src/odb/test/check_3dblox.ok new file mode 100644 index 00000000000..7efb2e0f2ae --- /dev/null +++ b/src/odb/test/check_3dblox.ok @@ -0,0 +1,12 @@ +[INFO ODB-0227] LEF file: data/../Nangate45/Nangate45_tech.lef, created 22 layers, 27 vias +[INFO ODB-0227] LEF file: data/../Nangate45/fake_macros.lef, created 10 library cells +[INFO ODB-0227] LEF file: data/../Nangate45/fake_bumps.lef, created 1 library cells +[WARNING STA-1171] data/../Nangate45/fake_macros.lib line 32, default_max_transition is 0.0. +[INFO ODB-0128] Design: fake_macros +[INFO ODB-0131] Created 10 components and 32 component-terminals. +[INFO ODB-0133] Created 12 nets and 24 connections. +[WARNING ODB-0156] Found 1 overlapping chips +[WARNING ODB-0151] Found 1 floating chip sets +[WARNING ODB-0151] Found 2 floating chip sets +Summary 7 / 7 (100% pass) +pass diff --git a/src/odb/test/check_3dblox.tcl b/src/odb/test/check_3dblox.tcl new file mode 100644 index 00000000000..724eadaf1db --- /dev/null +++ b/src/odb/test/check_3dblox.tcl @@ -0,0 +1,71 @@ +source "helpers.tcl" + +proc get_3dblox_marker_count { sub_category_name } { + set top_chip [[ord::get_db] getChip] + set category [$top_chip findMarkerCategory "3DBlox"] + if { $category == "NULL" } { + return 0 + } + set sub_category [$category findMarkerCategory $sub_category_name] + if { $sub_category == "NULL" } { + return 0 + } + return [$sub_category getMarkerCount] +} + +# 1. Load clean design +read_3dbx "data/example.3dbx" +set db [ord::get_db] +set top_chip [$db getChip] + +# Get design info +set inst1 [$top_chip findChipInst "soc_inst"] +lassign [$inst1 getLoc] x1 y1 z1 +set master1 [$inst1 getMasterChip] +set w1 [$master1 getWidth] +set h1 [$master1 getHeight] +set t1 [$master1 getThickness] + +set inst2 [$top_chip findChipInst "soc_inst_duplicate"] + +# Verify it is clean initially +check "Initial overlap count" { get_3dblox_marker_count "Overlapping chips" } 0 +check "Initial floating count" { get_3dblox_marker_count "Floating chips" } 0 + +# 2. Test Partial Overlap +# Move inst2 to partially overlap with inst1 +set p [odb::Point3D] +$p set [expr $x1 + $w1 / 4] [expr $y1 + $h1 / 4] [expr $z1 + $t1 / 2] +$inst2 setLoc $p + +check_3dblox +check "Partial overlap detected" { get_3dblox_marker_count "Overlapping chips" } 1 + +# 3. Test Touching (Stacked Exactly) +# Place inst2 exactly on top of inst1 +$p set $x1 $y1 [expr $z1 + $t1] +$inst2 setLoc $p + +check_3dblox +check "Touching chips no overlap" { get_3dblox_marker_count "Overlapping chips" } 0 +check "Touching chips not floating" { get_3dblox_marker_count "Floating chips" } 0 + +# 4. Test Vertical Gap (Floating) +# Move inst2 slightly higher +$p set $x1 $y1 [expr $z1 + $t1 + 1] +$inst2 setLoc $p + +check_3dblox +check "Vertical gap detected as floating" { get_3dblox_marker_count "Floating chips" } 1 + +# 5. Test Multiple Floating Sets +# Create another chip far away +set inst3 [odb::dbChipInst_create $top_chip $master1 "inst3"] +$p set [expr $x1 + 10 * $w1] [expr $y1 + 10 * $h1] $z1 +$inst3 setLoc $p + +check_3dblox +# Should find 2 sets of floating chips (inst2 and inst3 are both separate from inst1) +check "Multiple floating sets detected" { get_3dblox_marker_count "Floating chips" } 2 + +exit_summary