From e8885c3eefd3ecaf8f74d1cd9ef33ae8b737d41a Mon Sep 17 00:00:00 2001 From: Matt Liberty Date: Mon, 22 Jun 2026 01:01:58 +0000 Subject: [PATCH] odb: migrate swap_master test from Tcl to C++ Replace the swap_master.tcl integration test with a focused C++ unit test, TestSwapMasterLeaf, covering dbInst::swapMaster(dbMaster*) (the leaf-cell master swap). The .tcl test only printed the post-swap master name and diffed it against a golden log. The unit test asserts the documented contract directly with semantic checks: - swapping to a master with an identical MTerm signature returns true, changes the master, and preserves iterm net connections (remapped by MTerm name); - swapping to an incompatible signature returns false and leaves the instance untouched (a failure path the .tcl test never exercised). Built on SimpleDbFixture, so it needs no input files. Fixture setup lives in SetUp() and null-pointer assertions guard dbInst::create and findITerm. Registered in both CMake (cpp/CMakeLists.txt) and Bazel (cpp/BUILD + the cpp_tests suite in test/BUILD). Removed swap_master.tcl and swap_master.ok and de-registered them from both build systems. Binding-level coverage of the swapMaster command remains in test_inst.tcl / test_inst.py. The existing TestSwapMaster.cpp covers the distinct dbModInst::swapMaster(dbModule*) overload. Signed-off-by: Matt Liberty --- src/odb/test/BUILD | 2 +- src/odb/test/CMakeLists.txt | 1 - src/odb/test/cpp/BUILD | 13 +++ src/odb/test/cpp/CMakeLists.txt | 3 + src/odb/test/cpp/TestSwapMasterLeaf.cpp | 104 ++++++++++++++++++++++++ src/odb/test/swap_master.ok | 18 ---- src/odb/test/swap_master.tcl | 14 ---- 7 files changed, 121 insertions(+), 34 deletions(-) create mode 100644 src/odb/test/cpp/TestSwapMasterLeaf.cpp delete mode 100644 src/odb/test/swap_master.ok delete mode 100644 src/odb/test/swap_master.tcl 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