diff --git a/src/odb/test/BUILD b/src/odb/test/BUILD index 4b91ccbab4a..7fbad65d368 100644 --- a/src/odb/test/BUILD +++ b/src/odb/test/BUILD @@ -204,7 +204,6 @@ COMPULSORY_TESTS = [ "row_settings", "sky130hd_multi_patterned", "smash_vias", - "swap_master", "transform", "wire_encoder", "write_cdl", @@ -445,6 +444,7 @@ test_suite( "//src/odb/test/cpp:TestObjectType", "//src/odb/test/cpp:TestPolygonalFloorplan", "//src/odb/test/cpp:TestSwapMaster", + "//src/odb/test/cpp:TestSwapMasterLeaf", "//src/odb/test/cpp:TestSwapMasterUnusedPort", "//src/odb/test/cpp:TestWriteReadDbHier", ], diff --git a/src/odb/test/CMakeLists.txt b/src/odb/test/CMakeLists.txt index 5a7b994ee56..7bbbfd3d3be 100644 --- a/src/odb/test/CMakeLists.txt +++ b/src/odb/test/CMakeLists.txt @@ -60,7 +60,6 @@ or_integration_tests( row_settings sky130hd_multi_patterned smash_vias - swap_master transform wire_encoder write_cdl diff --git a/src/odb/test/cpp/BUILD b/src/odb/test/cpp/BUILD index 10d9d782281..ab234205da3 100644 --- a/src/odb/test/cpp/BUILD +++ b/src/odb/test/cpp/BUILD @@ -348,6 +348,19 @@ cc_test( ], ) +cc_test( + name = "TestSwapMasterLeaf", + srcs = [ + "TestSwapMasterLeaf.cpp", + ], + deps = [ + "//src/odb/src/db", + "//src/odb/test/cpp/helper", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +) + cc_test( name = "TestSwapMasterUnusedPort", srcs = [ diff --git a/src/odb/test/cpp/CMakeLists.txt b/src/odb/test/cpp/CMakeLists.txt index f314f4973ff..973b3677ef4 100644 --- a/src/odb/test/cpp/CMakeLists.txt +++ b/src/odb/test/cpp/CMakeLists.txt @@ -39,6 +39,7 @@ add_executable(Test3DBloxChecker Test3DBloxChecker.cpp Test3DBloxCheckerLogicalC add_executable(Test3DBloxVerilogWriter Test3DBloxVerilogWriter.cpp) add_executable(TestSwapMaster TestSwapMaster.cpp) add_executable(TestSwapMasterUnusedPort TestSwapMasterUnusedPort.cpp) +add_executable(TestSwapMasterLeaf TestSwapMasterLeaf.cpp) add_executable(TestWriteReadDbHier TestWriteReadDbHier.cpp) add_executable(TestObjectType TestObjectType.cpp) @@ -61,6 +62,7 @@ target_link_libraries(Test3DBloxChecker ${TEST_LIBS}) target_link_libraries(Test3DBloxVerilogWriter ${TEST_LIBS}) target_link_libraries(TestSwapMaster ${TEST_LIBS}) target_link_libraries(TestSwapMasterUnusedPort ${TEST_LIBS}) +target_link_libraries(TestSwapMasterLeaf ${TEST_LIBS}) target_link_libraries(TestWriteReadDbHier ${TEST_LIBS}) target_link_libraries(TestObjectType ${TEST_LIBS}) @@ -91,6 +93,7 @@ add_dependencies(build_and_test Test3DBloxVerilogWriter TestSwapMaster TestSwapMasterUnusedPort + TestSwapMasterLeaf TestWriteReadDbHier OdbGTests TestObjectType diff --git a/src/odb/test/cpp/TestSwapMasterLeaf.cpp b/src/odb/test/cpp/TestSwapMasterLeaf.cpp new file mode 100644 index 00000000000..0cda1cefe89 --- /dev/null +++ b/src/odb/test/cpp/TestSwapMasterLeaf.cpp @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2026, The OpenROAD Authors + +// Unit tests for dbInst::swapMaster(dbMaster*), the leaf-cell master swap. +// +// This replaces the integration test swap_master.tcl, which only printed +// the post-swap master name and diffed it against a golden log. Here we +// assert the documented contract directly: the return value, that the +// master actually changes, that existing iterm connections are preserved by +// MTerm name, and that an incompatible signature is rejected without +// mutating the instance. (Binding-level coverage of the swapMaster command +// remains in test_inst.tcl / test_inst.py.) +// +// NOTE: dbModInst::swapMaster(dbModule*) (the module-instance overload) is a +// different API covered by TestSwapMaster.cpp. + +#include "gtest/gtest.h" +#include "helper.h" +#include "odb/db.h" + +namespace odb { + +namespace { + +class SwapMasterLeafTest : public SimpleDbFixture +{ + protected: + void SetUp() override + { + SimpleDbFixture::SetUp(); + // createSimpleDB() builds: + // and2 : MTerms a, b, o (2x1) + // or2 : MTerms a, b, o (2x1, same signature as and2) + // inv1 : MTerms ip0, op0 (1x1, different signature) + createSimpleDB(); + block_ = db_->getChip()->getBlock(); + lib_ = db_->findLib("lib1"); + } + + dbBlock* block_ = nullptr; + dbLib* lib_ = nullptr; +}; + +// Swapping to a master with an identical MTerm signature succeeds, changes the +// master, and preserves every iterm's net connection (remapped by MTerm name). +TEST_F(SwapMasterLeafTest, SwapToCompatibleMasterPreservesConnections) +{ + dbMaster* and2 = lib_->findMaster("and2"); + dbMaster* or2 = lib_->findMaster("or2"); + ASSERT_NE(and2, nullptr); + ASSERT_NE(or2, nullptr); + + dbInst* inst = dbInst::create(block_, and2, "i1"); + ASSERT_NE(inst, nullptr); + auto [na, nb, no] = makeNets<3>(block_, {"na", "nb", "no"}); + dbITerm* a = inst->findITerm("a"); + dbITerm* b = inst->findITerm("b"); + dbITerm* o = inst->findITerm("o"); + ASSERT_NE(a, nullptr); + ASSERT_NE(b, nullptr); + ASSERT_NE(o, nullptr); + a->connect(na); + b->connect(nb); + o->connect(no); + + ASSERT_EQ(inst->getMaster(), and2); + + const bool swapped = inst->swapMaster(or2); + + EXPECT_TRUE(swapped); + EXPECT_EQ(inst->getMaster(), or2); + // Connections survive the swap, matched to the new master by MTerm name. + dbITerm* swapped_a = inst->findITerm("a"); + dbITerm* swapped_b = inst->findITerm("b"); + dbITerm* swapped_o = inst->findITerm("o"); + ASSERT_NE(swapped_a, nullptr); + ASSERT_NE(swapped_b, nullptr); + ASSERT_NE(swapped_o, nullptr); + EXPECT_EQ(swapped_a->getNet(), na); + EXPECT_EQ(swapped_b->getNet(), nb); + EXPECT_EQ(swapped_o->getNet(), no); +} + +// Swapping to a master whose MTerm signature differs is rejected: swapMaster +// returns false and leaves the instance untouched. +TEST_F(SwapMasterLeafTest, SwapToIncompatibleMasterIsRejected) +{ + dbMaster* and2 = lib_->findMaster("and2"); + dbMaster* inv1 = lib_->findMaster("inv1"); + ASSERT_NE(and2, nullptr); + ASSERT_NE(inv1, nullptr); + + dbInst* inst = dbInst::create(block_, and2, "i1"); + ASSERT_NE(inst, nullptr); + + const bool swapped = inst->swapMaster(inv1); + + EXPECT_FALSE(swapped); + EXPECT_EQ(inst->getMaster(), and2); +} + +} // namespace + +} // namespace odb diff --git a/src/odb/test/swap_master.ok b/src/odb/test/swap_master.ok deleted file mode 100644 index 46675cf76a2..00000000000 --- a/src/odb/test/swap_master.ok +++ /dev/null @@ -1,18 +0,0 @@ -[INFO ODB-0388] unsupported contactResistance property for layer contact :"10.5" -[INFO ODB-0388] unsupported contactResistance property for layer via1 :"5.69" -[WARNING ODB-0423] LEF58_REGION layer via1R1 ignored -[INFO ODB-0388] unsupported contactResistance property for layer via2 :"11.39" -[INFO ODB-0388] unsupported contactResistance property for layer via3 :"16.73" -[INFO ODB-0388] unsupported contactResistance property for layer via4 :"21.44" -[INFO ODB-0388] unsupported contactResistance property for layer via5 :"24.08" -[INFO ODB-0388] unsupported contactResistance property for layer via6 :"11.39" -[INFO ODB-0388] unsupported contactResistance property for layer via7 :"5.69" -[INFO ODB-0388] unsupported contactResistance property for layer via8 :"16.73" -[INFO ODB-0388] unsupported contactResistance property for layer via9 :"21.44" -[INFO ODB-0227] LEF file: data/gscl45nm.lef, created 22 layers, 14 vias, 33 library cells -[INFO ODB-0128] Design: counter -[INFO ODB-0130] Created 12 pins. -[INFO ODB-0131] Created 12 components and 60 component-terminals. -[INFO ODB-0133] Created 24 nets and 45 connections. -New inst master NAND2X1 -pass diff --git a/src/odb/test/swap_master.tcl b/src/odb/test/swap_master.tcl deleted file mode 100644 index 4d283679343..00000000000 --- a/src/odb/test/swap_master.tcl +++ /dev/null @@ -1,14 +0,0 @@ -source "helpers.tcl" - - -read_lef "data/gscl45nm.lef" -read_def "data/design.def" - -set inst [[ord::get_db_block] findInst _g0_] -set new_master [[ord::get_db] findMaster NAND2X1] -$inst swapMaster $new_master - -puts "New inst master [[$inst getMaster] getName]" - -puts "pass" -exit 0