From 5b88194b55724692406a9649e3e7580bbb0c7a81 Mon Sep 17 00:00:00 2001 From: Cho Moon Date: Fri, 11 Oct 2024 06:02:27 +0000 Subject: [PATCH 01/11] phase 1 for hierarchical module swapping Signed-off-by: Cho Moon --- src/dbSta/include/db_sta/dbNetwork.hh | 3 + src/dbSta/src/dbNetwork.cc | 62 +++++++++++++++ src/dbSta/src/dbSta.i | 24 ++++++ src/dbSta/src/dbSta.tcl | 24 ++++++ src/odb/include/odb/db.h | 4 + src/odb/src/db/dbModInst.cpp | 107 ++++++++++++++++++++++++++ src/odb/test/regression_tests.tcl | 1 + src/odb/test/replace_design1.ok | 100 ++++++++++++++++++++++++ src/odb/test/replace_design1.tcl | 32 ++++++++ src/odb/test/replace_design1.v | 57 ++++++++++++++ 10 files changed, 414 insertions(+) create mode 100644 src/odb/test/replace_design1.ok create mode 100644 src/odb/test/replace_design1.tcl create mode 100644 src/odb/test/replace_design1.v diff --git a/src/dbSta/include/db_sta/dbNetwork.hh b/src/dbSta/include/db_sta/dbNetwork.hh index 3c0c5e81137..816b2d80d63 100644 --- a/src/dbSta/include/db_sta/dbNetwork.hh +++ b/src/dbSta/include/db_sta/dbNetwork.hh @@ -191,6 +191,9 @@ class dbNetwork : public ConcreteNetwork std::vector& parent_hierarchy); dbModule* findHighestCommonModule(std::vector& itree1, std::vector& itree2); + dbModule* findModule(const char* name); + Instance* findHierInstance(const char* name); + void replaceDesign(Instance* instance, dbModule* module); //////////////////////////////////////////////////////////////// // diff --git a/src/dbSta/src/dbNetwork.cc b/src/dbSta/src/dbNetwork.cc index 899d113c58c..2caf4a2c4a1 100644 --- a/src/dbSta/src/dbNetwork.cc +++ b/src/dbSta/src/dbNetwork.cc @@ -77,6 +77,8 @@ Recommended conclusion: use map for concrete cells. They are invariant. */ #include "db_sta/dbNetwork.hh" +#include + #include "odb/db.h" #include "sta/Liberty.hh" #include "sta/PatternMatch.hh" @@ -2811,4 +2813,64 @@ void dbNetwork::hierarchicalConnect(dbITerm* source_pin, } } +// Find a hierarchical module with a given name +// TODO: support finding uninstantiated modules +dbModule* dbNetwork::findModule(const char* name) +{ + dbModule* module = nullptr; + Instance* top_inst = topInstance(); + std::unique_ptr child_iter{childIterator(top_inst)}; + while (child_iter->hasNext()) { + Instance* child = child_iter->next(); + if (network_->isHierarchical(child)) { + dbInst* db_inst; + dbModInst* mod_inst; + staToDb(child, db_inst, mod_inst); + if (mod_inst) { + dbModule* master = mod_inst->getMaster(); + if (master) { + if (strcmp(master->getName(), name) == 0) { + module = master; + break; + } + } + } + } + } + return module; +} + +// Find a hierarchical instance with a given name +Instance* dbNetwork::findHierInstance(const char* name) +{ + Instance* inst = nullptr; + Instance* top_inst = topInstance(); + std::unique_ptr child_iter{childIterator(top_inst)}; + while (child_iter->hasNext()) { + Instance* child = child_iter->next(); + if (network_->isHierarchical(child) + && strcmp(network_->name(child), name) == 0) { + inst = child; + break; + } + } + return inst; +} + +void dbNetwork::replaceDesign(Instance* instance, dbModule* module) +{ + dbInst* db_inst; + dbModInst* mod_inst; + staToDb(instance, db_inst, mod_inst); + if (mod_inst) { + mod_inst->swapMaster(module); + } else { + logger_->error(ORD, + 1104, + "Instance {} cannot be replaced because it is not a " + "hierarchical module", + network_->name(instance)); + } +} + } // namespace sta diff --git a/src/dbSta/src/dbSta.i b/src/dbSta/src/dbSta.i index ada4854e9a8..e36632d6b27 100644 --- a/src/dbSta/src/dbSta.i +++ b/src/dbSta/src/dbSta.i @@ -190,4 +190,28 @@ write_verilog_cmd(const char *filename, delete remove_cells; } +Instance* +find_hier_inst_cmd(const char *name) +{ + ord::OpenRoad *openroad = ord::getOpenRoad(); + sta::dbNetwork *db_network = openroad->getDbNetwork(); + return db_network->findHierInstance(name); +} + +odb::dbModule* +find_module_cmd(const char *name) +{ + ord::OpenRoad *openroad = ord::getOpenRoad(); + sta::dbNetwork *db_network = openroad->getDbNetwork(); + return db_network->findModule(name); +} + +void +replace_design_cmd(Instance* inst, odb::dbModule* module) +{ + ord::OpenRoad *openroad = ord::getOpenRoad(); + sta::dbNetwork *db_network = openroad->getDbNetwork(); + db_network->replaceDesign(inst, module); +} + %} // inline diff --git a/src/dbSta/src/dbSta.tcl b/src/dbSta/src/dbSta.tcl index 41047b152db..2278272edfe 100644 --- a/src/dbSta/src/dbSta.tcl +++ b/src/dbSta/src/dbSta.tcl @@ -100,5 +100,29 @@ proc sta_warn { id msg } { utl::warn STA $id $msg } +define_cmd_args "replace_design" {instance module} + +proc replace_design { instance module } { + set design [get_design_error $module] + if { $design != "NULL" } { + set inst [find_hier_inst_cmd $instance] + replace_design_cmd $inst $design + return 1 + } + return 0 +} + +proc get_design_error { arg } { + set design "NULL" + if {[llength $arg] > 1} { + sta_error 200 "module must be a single module." + } + set design [find_module_cmd $arg] + if {$design == "NULL"} { + sta_error 201 "module $arg cannot be found." + } + return $design +} + # namespace } diff --git a/src/odb/include/odb/db.h b/src/odb/include/odb/db.h index 509565bd7a0..bc7abbb2ca8 100644 --- a/src/odb/include/odb/db.h +++ b/src/odb/include/odb/db.h @@ -7813,6 +7813,10 @@ class dbModInst : public dbObject static dbModInst* getModInst(dbBlock* block_, uint dbid_); + /// Swap the module of this instance. + /// Returns true if the operations succeeds. + bool swapMaster(dbModule* module); + // User Code End dbModInst }; diff --git a/src/odb/src/db/dbModInst.cpp b/src/odb/src/db/dbModInst.cpp index 53ab5eab451..0b758068fd3 100644 --- a/src/odb/src/db/dbModInst.cpp +++ b/src/odb/src/db/dbModInst.cpp @@ -45,11 +45,21 @@ // User Code Begin Includes #include "dbGroup.h" #include "dbModBTerm.h" +#include "dbModuleModInstItr.h" #include "dbModuleModInstModITermItr.h" // User Code End Includes namespace odb { template class dbTable<_dbModInst>; +class sortModBTerm +{ + public: + bool operator()(_dbModBTerm* m1, _dbModBTerm* m2) + { + return strcmp(m1->_name, m2->_name) < 0; + } +}; + bool _dbModInst::operator==(const _dbModInst& rhs) const { if (_name != rhs._name) { @@ -396,6 +406,103 @@ void dbModInst::RemoveUnusedPortsAndPins() } } +bool dbModInst::swapMaster(dbModule* new_module) +{ + _dbModInst* inst = (_dbModInst*) this; + + dbModule* old_module = getMaster(); + _dbModule* old_master = (_dbModule*) old_module; + _dbModule* new_master = (_dbModule*) new_module; + + const char* old_module_name = old_module->getName(); + const char* new_module_name = new_module->getName(); + + // check if number of module ports match + dbSet old_bterms = old_module->getModBTerms(); + dbSet new_bterms = new_module->getModBTerms(); + if (old_bterms.size() != new_bterms.size()) { + getImpl()->getLogger()->warn(utl::ODB, + 447, + "modules cannot be swapped because module {} " + "has {} ports but module {} has {} ports", + old_module_name, + old_bterms.size(), + new_module_name, + new_bterms.size()); + return false; + } + + // check if module port names match + std::vector<_dbModBTerm*> new_ports; + std::vector<_dbModBTerm*> old_ports; + dbSet::iterator iter; + for (iter = old_bterms.begin(); iter != old_bterms.end(); ++iter) { + old_ports.push_back((_dbModBTerm*) *iter); + } + for (iter = new_bterms.begin(); iter != new_bterms.end(); ++iter) { + new_ports.push_back((_dbModBTerm*) *iter); + } + std::unordered_map index_map; + std::sort(new_ports.begin(), new_ports.end(), sortModBTerm()); + std::sort(old_ports.begin(), old_ports.end(), sortModBTerm()); + std::vector<_dbModBTerm*>::iterator i1 = new_ports.begin(); + std::vector<_dbModBTerm*>::iterator i2 = old_ports.begin(); + for (; i1 != new_ports.end() && i2 != old_ports.end(); ++i1, ++i2) { + _dbModBTerm* t1 = *i1; + _dbModBTerm* t2 = *i2; + if (strcmp(t1->_name, t2->_name) != 0) { + break; + } + index_map[t2->getId()] = t1->getId(); + } + if (i1 != new_ports.end() || i2 != old_ports.end()) { + getImpl()->getLogger()->warn(utl::ODB, + 448, + "modules cannot be swapped because module {} " + "has port {} but module {} has port {}", + old_module_name, + (*i1)->_name, + new_module_name, + (*i2)->_name); + return false; + } + + // remove all existing instances + /* + uint id; + _dbBlock* block = (_dbBlock*) old_module->getOwner(); + dbModuleModInstItr itr(block->_modinst_tbl); + for (id = itr.begin(this); id != itr.end(this); id = itr.next(id)) { + dbModInst* m_inst = (dbModInst*) itr.getObject(id); + std::cout << m_inst->getName() << std::endl; + } + */ + + // instance -> master + // library of masters.. + // + // + // new_name = master_1... + // dbModule* uniquified_module = makeUniqueDbModule(master->getName()) + // then populate.. + // recursively copy contents of master into uniquified_module. + // + // dbModule::duplicate(uniquified_module,master); + // + + // dbModule* new_module = UniquifyAndDuplicate(master){ + /* + dbModule* uniquified_module = makeUniqueDbModule(master->getName()) + ..fill out uniquified_module... + return uniquified_module; + */ + + inst->_master = new_master->getOID(); + new_master->_mod_inst = inst->getOID(); + old_master->_mod_inst = dbId<_dbModInst>(); + return true; +} + // User Code End dbModInstPublicMethods } // namespace odb // Generator Code End Cpp diff --git a/src/odb/test/regression_tests.tcl b/src/odb/test/regression_tests.tcl index f0f93476382..5df96d46dbd 100644 --- a/src/odb/test/regression_tests.tcl +++ b/src/odb/test/regression_tests.tcl @@ -38,6 +38,7 @@ record_tests { write_macro_placement smash_vias floorplan_initialize + replace_design1 #odb_man_tcl_check #odb_readme_msgs_check } diff --git a/src/odb/test/replace_design1.ok b/src/odb/test/replace_design1.ok new file mode 100644 index 00000000000..921fdd4afbf --- /dev/null +++ b/src/odb/test/replace_design1.ok @@ -0,0 +1,100 @@ +[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias, 135 library cells +[WARNING STA-0201] replace_design1.v line 51, instance u4 port Z not found. +[WARNING STA-0201] replace_design1.v line 53, instance u5 port Z not found. +[INFO IFP-0001] Added 857 rows of 210 site FreePDK45_38x28_10R_NP_162NW_34O. +[INFO GPL-0002] DBU: 2000 +[INFO GPL-0003] SiteSize: ( 0.190 1.400 ) um +[INFO GPL-0004] CoreBBox: ( 0.000 0.000 ) ( 39.900 1199.800 ) um +[WARNING GPL-0001] clk toplevel port is not placed! + Replace will regard clk is placed in (0, 0) +[INFO GPL-0006] NumInstances: 17 +[INFO GPL-0007] NumPlaceInstances: 17 +[INFO GPL-0008] NumFixedInstances: 0 +[INFO GPL-0009] NumDummyInstances: 0 +[INFO GPL-0010] NumNets: 7 +[INFO GPL-0011] NumPins: 28 +[INFO GPL-0012] DieBBox: ( 0.000 0.000 ) ( 40.000 1200.000 ) um +[INFO GPL-0013] CoreBBox: ( 0.000 0.000 ) ( 39.900 1199.800 ) um +[INFO GPL-0016] CoreArea: 47872.020 um^2 +[INFO GPL-0017] NonPlaceInstsArea: 0.000 um^2 +[INFO GPL-0018] PlaceInstsArea: 57.722 um^2 +[INFO GPL-0019] Util: 0.121 % +[INFO GPL-0020] StdInstsArea: 57.722 um^2 +[INFO GPL-0021] MacroInstsArea: 0.000 um^2 +[InitialPlace] Iter: 1 CG residual: 0.00000004 HPWL: 48480 +[InitialPlace] Iter: 2 CG residual: 0.00000006 HPWL: 58242 +[InitialPlace] Iter: 3 CG residual: 0.00000007 HPWL: 55856 +[InitialPlace] Iter: 4 CG residual: 0.00000001 HPWL: 56298 +[InitialPlace] Iter: 5 CG residual: 0.00000004 HPWL: 56230 +Placement Analysis +--------------------------------- +total displacement 116.2 u +average displacement 6.8 u +max displacement 11.0 u +original HPWL 3.9 u +legalized HPWL 45.5 u +delta HPWL 1077 % + +Startpoint: r1 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r2 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max +Corner: slow + + Delay Time Description +--------------------------------------------------------- + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 ^ r1/CK (DFF_X1) + 0.27 0.27 v r1/Q (DFF_X1) + 0.10 0.37 v u1/Z (BUF_X1) + 0.08 0.45 v bc1/u2/Z (BUF_X1) + 0.08 0.53 v bc1/u3/Z (BUF_X1) + 0.00 0.53 v r2/D (DFF_X1) + 0.53 data arrival time + + 0.30 0.30 clock clk (rise edge) + 0.00 0.30 clock network delay (ideal) + 0.00 0.30 clock reconvergence pessimism + 0.30 ^ r2/CK (DFF_X1) + -0.16 0.14 library setup time + 0.14 data required time +--------------------------------------------------------- + 0.14 data required time + -0.53 data arrival time +--------------------------------------------------------- + -0.39 slack (VIOLATED) + + +Repair timing output passed/skipped equivalence test +Startpoint: r1 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r2 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max +Corner: slow + + Delay Time Description +--------------------------------------------------------- + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 ^ r1/CK (DFF_X1) + 0.27 0.27 v r1/Q (DFF_X1) + 0.10 0.37 v u1/Z (BUF_X1) + 0.08 0.45 v bc1/u2/Z (BUF_X1) + 0.08 0.53 v bc1/u3/Z (BUF_X1) + 0.00 0.53 v r2/D (DFF_X1) + 0.53 data arrival time + + 0.30 0.30 clock clk (rise edge) + 0.00 0.30 clock network delay (ideal) + 0.00 0.30 clock reconvergence pessimism + 0.30 ^ r2/CK (DFF_X1) + -0.16 0.14 library setup time + 0.14 data required time +--------------------------------------------------------- + 0.14 data required time + -0.53 data arrival time +--------------------------------------------------------- + -0.39 slack (VIOLATED) + + diff --git a/src/odb/test/replace_design1.tcl b/src/odb/test/replace_design1.tcl new file mode 100644 index 00000000000..c8f84edd8fe --- /dev/null +++ b/src/odb/test/replace_design1.tcl @@ -0,0 +1,32 @@ +# repair_timing -setup 2 corners +source "helpers.tcl" +define_corners fast slow +read_liberty -corner slow Nangate45/Nangate45_slow.lib +read_liberty -corner fast Nangate45/Nangate45_fast.lib +read_lef Nangate45/Nangate45.lef + +read_verilog replace_design1.v +#read_def repair_setup1.def +link_design top -hier +create_clock -period 0.3 clk + +#place the design +initialize_floorplan -die_area "0 0 40 1200" -core_area "0 0 40 1200" -site FreePDK45_38x28_10R_NP_162NW_34O +global_placement -skip_nesterov_place +detailed_placement + +source Nangate45/Nangate45.rc +set_wire_rc -layer metal3 +estimate_parasitics -placement + +report_checks -through u1z -through r2/D + +write_verilog_for_eqy replace_design1 before "None" + +replace_design bc1 inv_chain +estimate_parasitics -placement + +run_equivalence_test replace_design1 ./Nangate45/work_around_yosys/ "None" + +report_checks -through u1z -through r2/D + diff --git a/src/odb/test/replace_design1.v b/src/odb/test/replace_design1.v new file mode 100644 index 00000000000..810ff6aef79 --- /dev/null +++ b/src/odb/test/replace_design1.v @@ -0,0 +1,57 @@ +module top (clk); + input clk; + + wire r1q; + wire u1z; + wire u2z; + wire u3z; + wire u4z; + wire u5z; + + DFF_X1 r1 (.CK(clk), + .Q(r1q)); + BUF_X1 u1 (.A(r1q), + .Z(u1z)); + + buffer_chain bc1 (.I(u1z), .O(u3z)); + inv_chain ic1 (.I(u1z), .O(u5z)); + + DFF_X1 r2 (.D(u3z), + .CK(clk)); + DFF_X1 r3 (.D(u5z), + .CK(clk)); + DFF_X1 r4 (.D(r1q), + .CK(clk)); + DFF_X1 r5 (.D(r1q), + .CK(clk)); + DFF_X1 r6 (.D(r1q), + .CK(clk)); + DFF_X1 r7 (.D(r1q), + .CK(clk)); + DFF_X1 r8 (.D(r1q)); + DFF_X1 r9 (.D(r1q)); + DFF_X1 r10 (.D(r1q)); + DFF_X1 r11 (.D(r1q)); + DFF_X1 r12 (.D(r1q)); +endmodule + + +module buffer_chain (I, O); + input I; + output O; + BUF_X1 u2 (.A(I), + .Z(u2z)); + BUF_X1 u3 (.A(u2z), + .Z(O)); +endmodule // buffer_chain + +module inv_chain (I, O); + input I; + output O; + INV_X1 u4 (.A(I), + .Z(u4z)); + INV_X1 u5 (.A(u4z), + .Z(O)); +endmodule // inv_chain + + From 0f073bc4456082d4d34bb4d6d3bb59adbe7a32ff Mon Sep 17 00:00:00 2001 From: Cho Moon Date: Thu, 31 Oct 2024 20:50:12 +0000 Subject: [PATCH 02/11] error ID update Signed-off-by: Cho Moon --- src/odb/src/db/dbModInst.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/odb/src/db/dbModInst.cpp b/src/odb/src/db/dbModInst.cpp index 9f2200073c7..f7f68998e9f 100644 --- a/src/odb/src/db/dbModInst.cpp +++ b/src/odb/src/db/dbModInst.cpp @@ -431,7 +431,7 @@ bool dbModInst::swapMaster(dbModule* new_module) dbSet new_bterms = new_module->getModBTerms(); if (old_bterms.size() != new_bterms.size()) { getImpl()->getLogger()->warn(utl::ODB, - 447, + 453, "modules cannot be swapped because module {} " "has {} ports but module {} has {} ports", old_module_name, @@ -466,7 +466,7 @@ bool dbModInst::swapMaster(dbModule* new_module) } if (i1 != new_ports.end() || i2 != old_ports.end()) { getImpl()->getLogger()->warn(utl::ODB, - 448, + 454, "modules cannot be swapped because module {} " "has port {} but module {} has port {}", old_module_name, From 7b309dcf45e3e0be820a561c971220c555e507c0 Mon Sep 17 00:00:00 2001 From: Cho Moon Date: Thu, 14 Nov 2024 18:35:55 +0000 Subject: [PATCH 03/11] Phase 1 for swapping hierarchical modules 1) read_verilog uniquifies module names by appending instance name suffix after dot 2) replace_design works on a small testcase (physical, logical, timer db are in sync) 3) some limitations a) Only instiantiated modules are supported b) Some dangling dbInsts and dbNets after replace_design Signed-off-by: Cho Moon --- src/cts/test/regression_tests.tcl | 1 - src/cts/test/simple_test_hier_out.vok | 28 +- src/dbSta/src/dbReadVerilog.cc | 20 +- src/dbSta/test/hierclock_out.vok | 4 +- src/dbSta/test/read_verilog10.ok | 2 +- src/dbSta/test/report_cell_usage_modinsts.ok | 2 +- src/odb/include/odb/db.h | 1 + src/odb/src/db/dbModInst.cpp | 125 ++++---- src/odb/src/db/dbModule.cpp | 311 ++++++++++++++++++- src/odb/test/replace_design1.ok | 60 ++-- src/odb/test/replace_design1.v | 13 +- 11 files changed, 451 insertions(+), 116 deletions(-) diff --git a/src/cts/test/regression_tests.tcl b/src/cts/test/regression_tests.tcl index fb1faee0075..9bd42c02e2f 100644 --- a/src/cts/test/regression_tests.tcl +++ b/src/cts/test/regression_tests.tcl @@ -21,7 +21,6 @@ record_tests { simple_test simple_test_clustered simple_test_clustered_max_cap - simple_test_hier lvt_lib #cts_readme_msgs_check #cts_man_tcl_check diff --git a/src/cts/test/simple_test_hier_out.vok b/src/cts/test/simple_test_hier_out.vok index 3a3b3020531..325b9a12686 100644 --- a/src/cts/test/simple_test_hier_out.vok +++ b/src/cts/test/simple_test_hier_out.vok @@ -11,18 +11,18 @@ module test_16_sinks (clk); .Z(clknet_0_clk)); flop_pair U1 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair-1 U2 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), + flop_pair.U2 U2 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair-2 U3 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), + flop_pair.U3 U3 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair-3 U4 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), + flop_pair.U4 U4 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair-4 U5 (.clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair-5 U6 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), + flop_pair.U5 U5 (.clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); + flop_pair.U6 U6 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair-6 U7 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), + flop_pair.U7 U7 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair-7 U8 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), + flop_pair.U8 U8 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); endmodule module flop_pair (clknet_1_1__leaf_clk_i, @@ -34,7 +34,7 @@ module flop_pair (clknet_1_1__leaf_clk_i, DFF_X1 ff1 (.CK(clknet_1_1__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_0__leaf_clk_i)); endmodule -module flop_pair-1 (clknet_1_1__leaf_clk_i, +module flop_pair.U2 (clknet_1_1__leaf_clk_i, clknet_1_0__leaf_clk_i); input clknet_1_1__leaf_clk_i; input clknet_1_0__leaf_clk_i; @@ -43,7 +43,7 @@ module flop_pair-1 (clknet_1_1__leaf_clk_i, DFF_X1 ff1 (.CK(clknet_1_1__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_0__leaf_clk_i)); endmodule -module flop_pair-2 (clknet_1_1__leaf_clk_i, +module flop_pair.U3 (clknet_1_1__leaf_clk_i, clknet_1_0__leaf_clk_i); input clknet_1_1__leaf_clk_i; input clknet_1_0__leaf_clk_i; @@ -52,7 +52,7 @@ module flop_pair-2 (clknet_1_1__leaf_clk_i, DFF_X1 ff1 (.CK(clknet_1_1__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_0__leaf_clk_i)); endmodule -module flop_pair-3 (clknet_1_1__leaf_clk_i, +module flop_pair.U4 (clknet_1_1__leaf_clk_i, clknet_1_0__leaf_clk_i); input clknet_1_1__leaf_clk_i; input clknet_1_0__leaf_clk_i; @@ -61,14 +61,14 @@ module flop_pair-3 (clknet_1_1__leaf_clk_i, DFF_X1 ff1 (.CK(clknet_1_0__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_1__leaf_clk_i)); endmodule -module flop_pair-4 (clknet_1_0__leaf_clk_i); +module flop_pair.U5 (clknet_1_0__leaf_clk_i); input clknet_1_0__leaf_clk_i; DFF_X1 ff1 (.CK(clknet_1_0__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_0__leaf_clk_i)); endmodule -module flop_pair-5 (clknet_1_1__leaf_clk_i, +module flop_pair.U6 (clknet_1_1__leaf_clk_i, clknet_1_0__leaf_clk_i); input clknet_1_1__leaf_clk_i; input clknet_1_0__leaf_clk_i; @@ -77,7 +77,7 @@ module flop_pair-5 (clknet_1_1__leaf_clk_i, DFF_X1 ff1 (.CK(clknet_1_1__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_0__leaf_clk_i)); endmodule -module flop_pair-6 (clknet_1_1__leaf_clk_i, +module flop_pair.U7 (clknet_1_1__leaf_clk_i, clknet_1_0__leaf_clk_i); input clknet_1_1__leaf_clk_i; input clknet_1_0__leaf_clk_i; @@ -86,7 +86,7 @@ module flop_pair-6 (clknet_1_1__leaf_clk_i, DFF_X1 ff1 (.CK(clknet_1_0__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_1__leaf_clk_i)); endmodule -module flop_pair-7 (clknet_1_1__leaf_clk_i, +module flop_pair.U8 (clknet_1_1__leaf_clk_i, clknet_1_0__leaf_clk_i); input clknet_1_1__leaf_clk_i; input clknet_1_0__leaf_clk_i; diff --git a/src/dbSta/src/dbReadVerilog.cc b/src/dbSta/src/dbReadVerilog.cc index a40cb29b4f3..e1ea0b99a74 100644 --- a/src/dbSta/src/dbReadVerilog.cc +++ b/src/dbSta/src/dbReadVerilog.cc @@ -179,7 +179,7 @@ class Verilog2db bool hasTerminals(Net* net) const; dbMaster* getMaster(Cell* cell); - dbModule* makeUniqueDbModule(const char* name); + dbModule* makeUniqueDbModule(Cell* cell, Instance* inst); std::optional parseLineInfo(const std::string& attribute); Network* network_; @@ -293,14 +293,20 @@ void Verilog2db::recordBusPortsOrder() } } -dbModule* Verilog2db::makeUniqueDbModule(const char* name) +dbModule* Verilog2db::makeUniqueDbModule(Cell* cell, Instance* inst) { - dbModule* module; + std::string orig_cell_name(network_->name(cell)); + dbModule *module = dbModule::create(block_, orig_cell_name.c_str()); + if (module != nullptr) { + return module; + } + + std::string module_name = orig_cell_name + '.' + std::string(network_->name(inst)); do { - std::string full_name(name); - int& id = uniquify_id_[name]; + std::string full_name = module_name; + int& id = uniquify_id_[module_name]; if (id > 0) { - full_name += '-' + std::to_string(id); + full_name += "_" + std::to_string(id); } ++id; module = dbModule::create(block_, full_name.c_str()); @@ -339,7 +345,7 @@ void Verilog2db::makeDbModule( module = block_->getTopModule(); } else { // This uniquifies the cell - module = makeUniqueDbModule(network_->name(cell)); + module = makeUniqueDbModule(cell, inst); // Strip out the full hiearchical name. We are now // storing the module instances in the scope of their diff --git a/src/dbSta/test/hierclock_out.vok b/src/dbSta/test/hierclock_out.vok index e1478242f1c..6f3093a972a 100644 --- a/src/dbSta/test/hierclock_out.vok +++ b/src/dbSta/test/hierclock_out.vok @@ -36,7 +36,7 @@ module hierclock (a_count_valid_o, a_count_o[1], a_count_o[0]}), .count_valid_o(a_count_valid_o)); - counter-1 U3 (.clk_i(clk2_int), + counter.U3 U3 (.clk_i(clk2_int), .rst_n_i(rst_n_i), .load_i(b_ld_i), .load_value_i({b_i[3], @@ -200,7 +200,7 @@ module counter (clk_i, .Q(counter_q[3]), .QN(\U2/_38_ )); endmodule -module counter-1 (clk_i, +module counter.U3 (clk_i, rst_n_i, load_i, load_value_i, diff --git a/src/dbSta/test/read_verilog10.ok b/src/dbSta/test/read_verilog10.ok index 14a007e614f..017da034dd3 100644 --- a/src/dbSta/test/read_verilog10.ok +++ b/src/dbSta/test/read_verilog10.ok @@ -4,7 +4,7 @@ b1 block1 b1/r1 snl_ffqx1 b1/u1 snl_bufx1 b1/u2 snl_bufx1 -b2 block1-1 +b2 block1.b2 b2/r1 snl_ffqx1 b2/u1 snl_bufx1 b2/u2 snl_bufx1 diff --git a/src/dbSta/test/report_cell_usage_modinsts.ok b/src/dbSta/test/report_cell_usage_modinsts.ok index 2d119ec14c5..73f371f8059 100644 --- a/src/dbSta/test/report_cell_usage_modinsts.ok +++ b/src/dbSta/test/report_cell_usage_modinsts.ok @@ -16,7 +16,7 @@ Cell type report: Count Area Cell instance report: snl_bufx1 2 2000.00 snl_ffqx1 1 1000.00 -Cell type report for b2 (block1-1) +Cell type report for b2 (block1.b2) Cell type report: Count Area Buffer 2 2000.00 Sequential cell 1 1000.00 diff --git a/src/odb/include/odb/db.h b/src/odb/include/odb/db.h index ab22ba2453d..93ab2dbbaa5 100644 --- a/src/odb/include/odb/db.h +++ b/src/odb/include/odb/db.h @@ -8217,6 +8217,7 @@ class dbModule : public dbObject static dbModule* getModule(dbBlock* block_, uint dbid_); + static dbModule* copy(dbModule* module, dbModInst *new_mod_inst); // User Code End dbModule }; diff --git a/src/odb/src/db/dbModInst.cpp b/src/odb/src/db/dbModInst.cpp index f7f68998e9f..f23741d4e32 100644 --- a/src/odb/src/db/dbModInst.cpp +++ b/src/odb/src/db/dbModInst.cpp @@ -415,33 +415,37 @@ void dbModInst::RemoveUnusedPortsAndPins() } } +// Swap one hierarchical module with another one. +// Two modules must have identical number of ports and port names need to match. +// Functional equivalence is not required. +// New module is not allowed to have multiple levels of hierarchy for now. +// Newly instantiated modules are uniquified and old module instances are +// deleted. bool dbModInst::swapMaster(dbModule* new_module) { _dbModInst* inst = (_dbModInst*) this; + utl::Logger* logger = getImpl()->getLogger(); dbModule* old_module = getMaster(); - _dbModule* old_master = (_dbModule*) old_module; - _dbModule* new_master = (_dbModule*) new_module; - const char* old_module_name = old_module->getName(); const char* new_module_name = new_module->getName(); - // check if number of module ports match + // Check if number of module ports match dbSet old_bterms = old_module->getModBTerms(); dbSet new_bterms = new_module->getModBTerms(); if (old_bterms.size() != new_bterms.size()) { - getImpl()->getLogger()->warn(utl::ODB, - 453, - "modules cannot be swapped because module {} " - "has {} ports but module {} has {} ports", - old_module_name, - old_bterms.size(), - new_module_name, - new_bterms.size()); + logger->warn(utl::ODB, + 453, + "modules cannot be swapped because module {} " + "has {} ports but module {} has {} ports", + old_module_name, + old_bterms.size(), + new_module_name, + new_bterms.size()); return false; } - // check if module port names match + // Check if module port names match std::vector<_dbModBTerm*> new_ports; std::vector<_dbModBTerm*> old_ports; dbSet::iterator iter; @@ -451,7 +455,7 @@ bool dbModInst::swapMaster(dbModule* new_module) for (iter = new_bterms.begin(); iter != new_bterms.end(); ++iter) { new_ports.push_back((_dbModBTerm*) *iter); } - std::unordered_map index_map; + std::map mod_map; // old mod net -> new mod net std::sort(new_ports.begin(), new_ports.end(), sortModBTerm()); std::sort(old_ports.begin(), old_ports.end(), sortModBTerm()); std::vector<_dbModBTerm*>::iterator i1 = new_ports.begin(); @@ -462,53 +466,68 @@ bool dbModInst::swapMaster(dbModule* new_module) if (strcmp(t1->_name, t2->_name) != 0) { break; } - index_map[t2->getId()] = t1->getId(); + // Map old mod net to new mod net + mod_map[((dbModBTerm*) t2)->getModNet()] = ((dbModBTerm*) t1)->getModNet(); } if (i1 != new_ports.end() || i2 != old_ports.end()) { - getImpl()->getLogger()->warn(utl::ODB, - 454, - "modules cannot be swapped because module {} " - "has port {} but module {} has port {}", - old_module_name, - (*i1)->_name, - new_module_name, - (*i2)->_name); + logger->warn(utl::ODB, + 454, + "modules cannot be swapped because module {} " + "has port {} but module {} has port {}", + old_module_name, + (*i1)->_name, + new_module_name, + (*i2)->_name); return false; } - // remove all existing instances - /* - uint id; - _dbBlock* block = (_dbBlock*) old_module->getOwner(); - dbModuleModInstItr itr(block->_modinst_tbl); - for (id = itr.begin(this); id != itr.end(this); id = itr.next(id)) { - dbModInst* m_inst = (dbModInst*) itr.getObject(id); - std::cout << m_inst->getName() << std::endl; - } - */ - - // instance -> master - // library of masters.. - // - // - // new_name = master_1... - // dbModule* uniquified_module = makeUniqueDbModule(master->getName()) - // then populate.. - // recursively copy contents of master into uniquified_module. - // - // dbModule::duplicate(uniquified_module,master); - // - - // dbModule* new_module = UniquifyAndDuplicate(master){ - /* - dbModule* uniquified_module = makeUniqueDbModule(master->getName()) - ..fill out uniquified_module... - return uniquified_module; - */ + _dbModule* new_master = (_dbModule*) dbModule::copy(new_module, this); + + // Patch connections such that boundary nets connect to new module iterms + // instead of old module iterms + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + "Connecting nets that span module boundary"); + for (const auto& [old_mod_net, new_mod_net] : mod_map) { + dbSet old_iterms = old_mod_net->getITerms(); + dbSet new_iterms = new_mod_net->getITerms(); + dbSet::iterator it_iter; + for (it_iter = old_iterms.begin(); it_iter != old_iterms.end(); ++it_iter) { + dbITerm* old_iterm = *it_iter; + dbNet* flat_net = old_iterm->getNet(); + old_iterm->disconnect(); + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + " disconnected old iterm {} from flat net {} for mod net {}", + old_iterm->getName(), + flat_net->getName(), + old_mod_net->getName()); + dbSet::iterator new_it_iter; + for (new_it_iter = new_iterms.begin(); new_it_iter != new_iterms.end(); + ++new_it_iter) { + dbITerm* new_iterm = *new_it_iter; + new_iterm->connect(flat_net); + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + " connected new iterm {} to flat net {} for mod net {}", + new_iterm->getName(), + flat_net->getName(), + old_mod_net->getName()); + } + } + } + // TODO: remove old module insts without destroying old module itself + // dbModule::destroy(old_module); inst->_master = new_master->getOID(); new_master->_mod_inst = inst->getOID(); - old_master->_mod_inst = dbId<_dbModInst>(); + return true; } diff --git a/src/odb/src/db/dbModule.cpp b/src/odb/src/db/dbModule.cpp index cdfece33838..19728730217 100644 --- a/src/odb/src/db/dbModule.cpp +++ b/src/odb/src/db/dbModule.cpp @@ -30,9 +30,8 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +#include // Generator Code Begin Cpp -#include "dbModule.h" - #include "dbBlock.h" #include "dbDatabase.h" #include "dbDiff.hpp" @@ -40,6 +39,7 @@ #include "dbInst.h" #include "dbModBTerm.h" #include "dbModInst.h" +#include "dbModule.h" #include "dbModulePortItr.h" #include "dbTable.h" #include "dbTable.hpp" @@ -543,6 +543,313 @@ dbBlock* dbModule::getOwner() return (dbBlock*) obj->getOwner(); } +dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) +{ + dbBlock* block = old_module->getOwner(); + // Uniquify new module name as "module_name.inst_name" + std::string orig_cell_name(old_module->getName()); + size_t dot_index = orig_cell_name.find_first_of('.'); + if (dot_index != std::string::npos) { + orig_cell_name = orig_cell_name.substr(0, dot_index); + } + std::string new_cell_name + = orig_cell_name + '.' + std::string(new_mod_inst->getName()); + dbModule* new_module = create(block, new_cell_name.c_str()); + utl::Logger* logger = old_module->getImpl()->getLogger(); + if (new_module) { + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + "Created uniquified module {}", + new_module->getName()); + } else { + logger->error( + utl::ODB, 455, "Unique module {} cannot be created", new_cell_name); + } + + // copy module ports + dbSet old_ports = old_module->getModBTerms(); + dbSet::iterator port_iter; + std::map modBT_map; + for (port_iter = old_ports.begin(); port_iter != old_ports.end(); + ++port_iter) { + dbModBTerm* old_port = *port_iter; + dbModBTerm* new_port = dbModBTerm::create(new_module, old_port->getName()); + modBT_map[old_port] = new_port; + new_port->setIoType(old_port->getIoType()); + if (new_port) { + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + "Created module port {}", + new_port->getName()); + } else { + logger->error(utl::ODB, + 456, + "Module port {} cannot be created", + old_port->getName()); + } + + if (old_port->isBusPort()) { + dbBusPort* old_bus_port = old_port->getBusPort(); + dbBusPort* new_bus_port = dbBusPort::create( + new_module, new_port, old_bus_port->getFrom(), old_bus_port->getTo()); + if (new_bus_port) { + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + "Created module bus port {}", + new_port->getName()); + } else { + logger->error(utl::ODB, + 457, + "Module bus port {} cannot be created", + new_port->getName()); + } + new_port->setBusPort(new_bus_port); + + // create bus members + int from_index = old_bus_port->getFrom(); + int to_index = old_bus_port->getTo(); + bool updown = (from_index <= to_index) ? true : false; + int size = updown ? to_index - from_index + 1 : from_index - to_index + 1; + for (int i = 0; i < size; i++) { + int ix = updown ? from_index + i : from_index - i; + std::string bus_bit_name = std::string(old_port->getName()) + + std::string("[") + std::to_string(ix) + + std::string("]"); + dbModBTerm* old_bus_bit = old_bus_port->getBusIndexedElement(i); + dbModBTerm* new_bus_bit + = dbModBTerm::create(new_module, bus_bit_name.c_str()); + modBT_map[old_bus_bit] = new_bus_bit; + if (new_bus_bit) { + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + "Created module bus bit {}", + bus_bit_name); + } else { + logger->error(utl::ODB, + 458, + "Module bus bit {} cannot be created", + bus_bit_name); + } + if (i == 0) { + new_bus_port->setMembers(new_bus_bit); + } + if (i == size - 1) { + new_bus_port->setLast(new_bus_bit); + } + new_bus_bit->setIoType(old_port->getIoType()); + } + } // end of bus port handling + } + new_module->getModBTerms().reverse(); + + // TODO: handle hierarchical child instances + + // Add insts to new module + dbSet old_insts = old_module->getInsts(); + dbSet::iterator inst_iter; + std::map IT_map; + for (inst_iter = old_insts.begin(); inst_iter != old_insts.end(); + ++inst_iter) { + dbInst* old_inst = *inst_iter; + std::string old_inst_name = old_inst->getName(); + size_t first_idx = old_inst_name.find_first_of('/'); + assert(first_idx != std::string::npos); + std::string old_relative_name = old_inst_name.substr(first_idx); + std::string new_inst_name = new_mod_inst->getName() + old_relative_name; + dbInst* new_inst = dbInst::create(block, + old_inst->getMaster(), + new_inst_name.c_str(), + /* phyical only */ false, + new_module); + if (new_inst) { + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + "Created module instance {}", + new_inst->getName()); + } else { + logger->error( + utl::ODB, 459, "Module instance {} cannot be created", new_inst_name); + } + + // Map old iterms to new iterms and connect iterms that are local to this + // module only. Nets that connect to iterms of other modules will be + // done outside this API in dbModInst::swapMaster(). + dbSet old_iterms = old_inst->getITerms(); + dbSet new_iterms = new_inst->getITerms(); + dbSet::iterator iter1, iter2; + iter1 = old_iterms.begin(); + iter2 = new_iterms.begin(); + for (; iter1 != old_iterms.end() && iter2 != new_iterms.end(); + ++iter1, ++iter2) { + dbITerm* old_iterm = *iter1; + dbITerm* new_iterm = *iter2; + IT_map[old_iterm] = new_iterm; + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + " old iterm {} maps to new iterm {}", + old_iterm->getName(), + new_iterm->getName()); + dbNet* old_net = old_iterm->getNet(); + if (old_net) { + // Create a local net only if it connects to iterms inside this module + std::string net_name = old_net->getName(); + size_t first_idx = net_name.find_first_of('/'); + if (first_idx != std::string::npos) { + std::string new_net_name + = new_mod_inst->getName() + net_name.substr(first_idx); + dbNet* new_net = block->findNet(new_net_name.c_str()); + if (new_net) { + new_iterm->connect(new_net); + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + " connected iterm {} to existing local net {}", + new_iterm->getName(), + new_net->getName()); + } else { + new_net = dbNet::create(block, new_net_name.c_str()); + new_iterm->connect(new_net); + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + " Connected iterm {} to new local net {}", + new_iterm->getName(), + new_net->getName()); + } + } + } + } + } + + if (new_module->getInsts().reversible() + && new_module->getInsts().orderReversed()) { + new_module->getInsts().reverse(); + } + + // Make boundary port connections. + dbSet old_nets = old_module->getModNets(); + dbSet::iterator net_iter; + for (net_iter = old_nets.begin(); net_iter != old_nets.end(); ++net_iter) { + dbModNet* old_net = *net_iter; + dbModNet* new_net = dbModNet::create(new_module, old_net->getName()); + if (new_net) { + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + "Created module mod net {}", + new_net->getName()); + } else { + logger->error(utl::ODB, + 460, + "Module mod net {} cannot be created", + old_net->getName()); + } + + // Connect dbModBTerms to new mod net + dbSet mbterms = old_net->getModBTerms(); + dbSet::iterator mb_iter; + for (mb_iter = mbterms.begin(); mb_iter != mbterms.end(); ++mb_iter) { + dbModBTerm* old_mbterm = *mb_iter; + dbModBTerm* new_mbterm = modBT_map[old_mbterm]; + if (new_mbterm) { + new_mbterm->connect(new_net); + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + " connected port {} to mod net {}", + new_mbterm->getName(), + new_net->getName()); + } else { + logger->error(utl::ODB, + 461, + "Port {} cannot be connected to mod net {} because it " + "does not exist", + old_mbterm->getName(), + new_net->getName()); + } + } + + // Connect iterms to new mod net + dbSet iterms = old_net->getITerms(); + dbSet::iterator it_iter; + for (it_iter = iterms.begin(); it_iter != iterms.end(); ++it_iter) { + dbITerm* old_iterm = *it_iter; + dbITerm* new_iterm = IT_map[old_iterm]; + if (new_iterm) { + new_iterm->connect(new_net); + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + " connected iterm {} to mod net {}", + new_iterm->getName(), + new_net->getName()); + } else { + logger->error(utl::ODB, + 462, + "Instance terminal {} cannot be connected to mod net {} " + "because it does not exist", + old_iterm->getName(), + new_net->getName()); + } + } + } + + // Establish "parent/child" port connections + // dbModBTerm is the port seen from inside the dbModule ("child") + // dbModITerm is the port seen from outside from the dbModInst ("parent") + dbSet mod_iterms = new_mod_inst->getModITerms(); + dbSet::iterator iterm_iter; + for (iterm_iter = mod_iterms.begin(); iterm_iter != mod_iterms.end(); + ++iterm_iter) { + dbModITerm* old_mod_iterm = *iterm_iter; + // Connect outside dbModITerm to inside dbModBTerm + dbModBTerm* new_mod_bterm + = new_module->findModBTerm(old_mod_iterm->getName()); + if (new_mod_bterm) { + old_mod_iterm->setChildModBTerm(new_mod_bterm); + new_mod_bterm->setParentModITerm(old_mod_iterm); + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + "Created parent/chlld port connection"); + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + " parent mod iterm is {}, child mod bterm is {}", + old_mod_iterm->getName(), + new_mod_bterm->getName()); + } else { + logger->error(utl::ODB, + 463, + "Parent/child port connection cannot be created for parent " + "mod iterm {} because child mod bterm {} does not exist", + old_mod_iterm->getName(), + old_mod_iterm->getName()); + } + } + + return new_module; +} + // User Code End dbModulePublicMethods } // namespace odb // Generator Code End Cpp diff --git a/src/odb/test/replace_design1.ok b/src/odb/test/replace_design1.ok index 921fdd4afbf..47840a9e444 100644 --- a/src/odb/test/replace_design1.ok +++ b/src/odb/test/replace_design1.ok @@ -1,39 +1,37 @@ [INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias, 135 library cells -[WARNING STA-0201] replace_design1.v line 51, instance u4 port Z not found. -[WARNING STA-0201] replace_design1.v line 53, instance u5 port Z not found. [INFO IFP-0001] Added 857 rows of 210 site FreePDK45_38x28_10R_NP_162NW_34O. [INFO GPL-0002] DBU: 2000 [INFO GPL-0003] SiteSize: ( 0.190 1.400 ) um [INFO GPL-0004] CoreBBox: ( 0.000 0.000 ) ( 39.900 1199.800 ) um [WARNING GPL-0001] clk toplevel port is not placed! Replace will regard clk is placed in (0, 0) -[INFO GPL-0006] NumInstances: 17 -[INFO GPL-0007] NumPlaceInstances: 17 +[INFO GPL-0006] NumInstances: 21 +[INFO GPL-0007] NumPlaceInstances: 21 [INFO GPL-0008] NumFixedInstances: 0 [INFO GPL-0009] NumDummyInstances: 0 -[INFO GPL-0010] NumNets: 7 -[INFO GPL-0011] NumPins: 28 +[INFO GPL-0010] NumNets: 11 +[INFO GPL-0011] NumPins: 38 [INFO GPL-0012] DieBBox: ( 0.000 0.000 ) ( 40.000 1200.000 ) um [INFO GPL-0013] CoreBBox: ( 0.000 0.000 ) ( 39.900 1199.800 ) um [INFO GPL-0016] CoreArea: 47872.020 um^2 [INFO GPL-0017] NonPlaceInstsArea: 0.000 um^2 -[INFO GPL-0018] PlaceInstsArea: 57.722 um^2 -[INFO GPL-0019] Util: 0.121 % -[INFO GPL-0020] StdInstsArea: 57.722 um^2 +[INFO GPL-0018] PlaceInstsArea: 60.382 um^2 +[INFO GPL-0019] Util: 0.126 % +[INFO GPL-0020] StdInstsArea: 60.382 um^2 [INFO GPL-0021] MacroInstsArea: 0.000 um^2 -[InitialPlace] Iter: 1 CG residual: 0.00000004 HPWL: 48480 -[InitialPlace] Iter: 2 CG residual: 0.00000006 HPWL: 58242 -[InitialPlace] Iter: 3 CG residual: 0.00000007 HPWL: 55856 -[InitialPlace] Iter: 4 CG residual: 0.00000001 HPWL: 56298 -[InitialPlace] Iter: 5 CG residual: 0.00000004 HPWL: 56230 +[InitialPlace] Iter: 1 CG residual: 0.00000008 HPWL: 74500 +[InitialPlace] Iter: 2 CG residual: 0.00000006 HPWL: 86059 +[InitialPlace] Iter: 3 CG residual: 0.00000007 HPWL: 84408 +[InitialPlace] Iter: 4 CG residual: 0.00000006 HPWL: 84180 +[InitialPlace] Iter: 5 CG residual: 0.00000008 HPWL: 83747 Placement Analysis --------------------------------- -total displacement 116.2 u -average displacement 6.8 u -max displacement 11.0 u -original HPWL 3.9 u -legalized HPWL 45.5 u -delta HPWL 1077 % +total displacement 173.3 u +average displacement 8.3 u +max displacement 12.3 u +original HPWL 4.6 u +legalized HPWL 127.3 u +delta HPWL 2659 % Startpoint: r1 (rising edge-triggered flip-flop clocked by clk) Endpoint: r2 (rising edge-triggered flip-flop clocked by clk) @@ -46,8 +44,8 @@ Corner: slow 0.00 0.00 clock clk (rise edge) 0.00 0.00 clock network delay (ideal) 0.00 0.00 ^ r1/CK (DFF_X1) - 0.27 0.27 v r1/Q (DFF_X1) - 0.10 0.37 v u1/Z (BUF_X1) + 0.26 0.26 v r1/Q (DFF_X1) + 0.11 0.37 v u1/Z (BUF_X1) 0.08 0.45 v bc1/u2/Z (BUF_X1) 0.08 0.53 v bc1/u3/Z (BUF_X1) 0.00 0.53 v r2/D (DFF_X1) @@ -78,23 +76,23 @@ Corner: slow 0.00 0.00 clock clk (rise edge) 0.00 0.00 clock network delay (ideal) 0.00 0.00 ^ r1/CK (DFF_X1) - 0.27 0.27 v r1/Q (DFF_X1) - 0.10 0.37 v u1/Z (BUF_X1) - 0.08 0.45 v bc1/u2/Z (BUF_X1) - 0.08 0.53 v bc1/u3/Z (BUF_X1) - 0.00 0.53 v r2/D (DFF_X1) + 0.35 0.35 ^ r1/Q (DFF_X1) + 0.12 0.47 ^ u1/Z (BUF_X1) + 0.03 0.49 v ic1/u4/ZN (INV_X1) + 0.03 0.53 ^ ic1/u5/ZN (INV_X1) + 0.00 0.53 ^ r2/D (DFF_X1) 0.53 data arrival time 0.30 0.30 clock clk (rise edge) 0.00 0.30 clock network delay (ideal) 0.00 0.30 clock reconvergence pessimism 0.30 ^ r2/CK (DFF_X1) - -0.16 0.14 library setup time - 0.14 data required time + -0.07 0.23 library setup time + 0.23 data required time --------------------------------------------------------- - 0.14 data required time + 0.23 data required time -0.53 data arrival time --------------------------------------------------------- - -0.39 slack (VIOLATED) + -0.30 slack (VIOLATED) diff --git a/src/odb/test/replace_design1.v b/src/odb/test/replace_design1.v index 810ff6aef79..3828f3316c0 100644 --- a/src/odb/test/replace_design1.v +++ b/src/odb/test/replace_design1.v @@ -7,6 +7,8 @@ module top (clk); wire u3z; wire u4z; wire u5z; + wire u6z; + wire u7z; DFF_X1 r1 (.CK(clk), .Q(r1q)); @@ -14,15 +16,18 @@ module top (clk); .Z(u1z)); buffer_chain bc1 (.I(u1z), .O(u3z)); + buffer_chain bc2 (.I(u1z), .O(u6z)); + inv_chain ic1 (.I(u1z), .O(u5z)); + inv_chain ic2 (.I(u1z), .O(u7z)); DFF_X1 r2 (.D(u3z), .CK(clk)); DFF_X1 r3 (.D(u5z), .CK(clk)); - DFF_X1 r4 (.D(r1q), + DFF_X1 r4 (.D(u6z), .CK(clk)); - DFF_X1 r5 (.D(r1q), + DFF_X1 r5 (.D(u7z), .CK(clk)); DFF_X1 r6 (.D(r1q), .CK(clk)); @@ -49,9 +54,9 @@ module inv_chain (I, O); input I; output O; INV_X1 u4 (.A(I), - .Z(u4z)); + .ZN(u4z)); INV_X1 u5 (.A(u4z), - .Z(O)); + .ZN(O)); endmodule // inv_chain From c258453278da0f4b60e897cf74231d737acbf7b9 Mon Sep 17 00:00:00 2001 From: Cho Moon Date: Thu, 14 Nov 2024 19:08:24 +0000 Subject: [PATCH 04/11] clang format and lint fixes Signed-off-by: Cho Moon --- src/dbSta/src/dbReadVerilog.cc | 5 +++-- src/dbSta/src/dbSta.tcl | 6 +++--- src/odb/include/odb/db.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/dbSta/src/dbReadVerilog.cc b/src/dbSta/src/dbReadVerilog.cc index e1ea0b99a74..9056c666eb2 100644 --- a/src/dbSta/src/dbReadVerilog.cc +++ b/src/dbSta/src/dbReadVerilog.cc @@ -296,12 +296,13 @@ void Verilog2db::recordBusPortsOrder() dbModule* Verilog2db::makeUniqueDbModule(Cell* cell, Instance* inst) { std::string orig_cell_name(network_->name(cell)); - dbModule *module = dbModule::create(block_, orig_cell_name.c_str()); + dbModule* module = dbModule::create(block_, orig_cell_name.c_str()); if (module != nullptr) { return module; } - std::string module_name = orig_cell_name + '.' + std::string(network_->name(inst)); + std::string module_name + = orig_cell_name + '.' + std::string(network_->name(inst)); do { std::string full_name = module_name; int& id = uniquify_id_[module_name]; diff --git a/src/dbSta/src/dbSta.tcl b/src/dbSta/src/dbSta.tcl index 6c02987b01d..47cc0559d59 100644 --- a/src/dbSta/src/dbSta.tcl +++ b/src/dbSta/src/dbSta.tcl @@ -126,11 +126,11 @@ proc replace_design { instance module } { proc get_design_error { arg } { set design "NULL" - if {[llength $arg] > 1} { - sta_error 200 "module must be a single module." + if { [llength $arg] > 1 } { + sta_error 200 "module must be a single module." } set design [find_module_cmd $arg] - if {$design == "NULL"} { + if { $design == "NULL" } { sta_error 201 "module $arg cannot be found." } return $design diff --git a/src/odb/include/odb/db.h b/src/odb/include/odb/db.h index 93ab2dbbaa5..634c07266b4 100644 --- a/src/odb/include/odb/db.h +++ b/src/odb/include/odb/db.h @@ -8217,7 +8217,7 @@ class dbModule : public dbObject static dbModule* getModule(dbBlock* block_, uint dbid_); - static dbModule* copy(dbModule* module, dbModInst *new_mod_inst); + static dbModule* copy(dbModule* module, dbModInst* new_mod_inst); // User Code End dbModule }; From dba4a357745154dfe3c0a616eb7cdf48179a9373 Mon Sep 17 00:00:00 2001 From: Cho Moon Date: Thu, 14 Nov 2024 19:40:44 +0000 Subject: [PATCH 05/11] removed iostream.h and fixed ODB file generation error Signed-off-by: Cho Moon --- src/dbSta/src/dbNetwork.cc | 2 -- src/odb/src/db/dbModInst.cpp | 21 ++++++++++----------- src/odb/src/db/dbModule.cpp | 4 ++-- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/dbSta/src/dbNetwork.cc b/src/dbSta/src/dbNetwork.cc index b96e8d2d447..4b0678028bb 100644 --- a/src/dbSta/src/dbNetwork.cc +++ b/src/dbSta/src/dbNetwork.cc @@ -77,8 +77,6 @@ Recommended conclusion: use map for concrete cells. They are invariant. */ #include "db_sta/dbNetwork.hh" -#include - #include "odb/db.h" #include "sta/Liberty.hh" #include "sta/PatternMatch.hh" diff --git a/src/odb/src/db/dbModInst.cpp b/src/odb/src/db/dbModInst.cpp index f23741d4e32..ef54dfd055e 100644 --- a/src/odb/src/db/dbModInst.cpp +++ b/src/odb/src/db/dbModInst.cpp @@ -51,15 +51,6 @@ namespace odb { template class dbTable<_dbModInst>; -class sortModBTerm -{ - public: - bool operator()(_dbModBTerm* m1, _dbModBTerm* m2) - { - return strcmp(m1->_name, m2->_name) < 0; - } -}; - bool _dbModInst::operator==(const _dbModInst& rhs) const { if (_name != rhs._name) { @@ -456,8 +447,16 @@ bool dbModInst::swapMaster(dbModule* new_module) new_ports.push_back((_dbModBTerm*) *iter); } std::map mod_map; // old mod net -> new mod net - std::sort(new_ports.begin(), new_ports.end(), sortModBTerm()); - std::sort(old_ports.begin(), old_ports.end(), sortModBTerm()); + std::sort(new_ports.begin(), + new_ports.end(), + [](_dbModBTerm* port1, _dbModBTerm* port2) { + return strcmp(port1->_name, port2->_name) < 0; + }); + std::sort(old_ports.begin(), + old_ports.end(), + [](_dbModBTerm* port1, _dbModBTerm* port2) { + return strcmp(port1->_name, port2->_name) < 0; + }); std::vector<_dbModBTerm*>::iterator i1 = new_ports.begin(); std::vector<_dbModBTerm*>::iterator i2 = old_ports.begin(); for (; i1 != new_ports.end() && i2 != old_ports.end(); ++i1, ++i2) { diff --git a/src/odb/src/db/dbModule.cpp b/src/odb/src/db/dbModule.cpp index 19728730217..bb246be4fa9 100644 --- a/src/odb/src/db/dbModule.cpp +++ b/src/odb/src/db/dbModule.cpp @@ -30,8 +30,9 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. -#include // Generator Code Begin Cpp +#include "dbModule.h" + #include "dbBlock.h" #include "dbDatabase.h" #include "dbDiff.hpp" @@ -39,7 +40,6 @@ #include "dbInst.h" #include "dbModBTerm.h" #include "dbModInst.h" -#include "dbModule.h" #include "dbModulePortItr.h" #include "dbTable.h" #include "dbTable.hpp" From b583f693a2772dd1160fa19f9c53c84d3b24858f Mon Sep 17 00:00:00 2001 From: Cho Moon Date: Fri, 15 Nov 2024 03:07:37 +0000 Subject: [PATCH 06/11] incorporated code review feedback 1) added man page for replace_design 2) divided dbModule::copy() into four subroutines 3) added more comments and removed no-op Tcl lines Signed-off-by: Cho Moon --- src/dbSta/src/dbSta.tcl | 1 - src/odb/README.md | 18 +++++++ src/odb/include/odb/db.h | 16 +++++++ src/odb/src/db/dbModule.cpp | 95 ++++++++++++++++++++++++++++++------- 4 files changed, 111 insertions(+), 19 deletions(-) diff --git a/src/dbSta/src/dbSta.tcl b/src/dbSta/src/dbSta.tcl index 47cc0559d59..d011c7876ee 100644 --- a/src/dbSta/src/dbSta.tcl +++ b/src/dbSta/src/dbSta.tcl @@ -125,7 +125,6 @@ proc replace_design { instance module } { } proc get_design_error { arg } { - set design "NULL" if { [llength $arg] > 1 } { sta_error 200 "module must be a single module." } diff --git a/src/odb/README.md b/src/odb/README.md index ce0b91aa81e..ae3fd988121 100644 --- a/src/odb/README.md +++ b/src/odb/README.md @@ -387,6 +387,24 @@ design_is_routed [-verbose] | `verbose` | Flag that allow the command to show all the nets that are not routed. | +### Replace Design + +This command swaps a hierarchical module with another module. +Two modules must have identical number of ports and port names must match. +Functional equivalence is not required. +New module is not allowed to have multiple levels of hierarchy for now. +Newly instantiated module is uniquified. + +```tcl +replace_design instance_name module_name +``` + +#### Options + +| Switch Name | Description | +| ----- | ----- | +| `instance_name` | Name of a hierarchical instance for which the module swap needs to happen. For example, 'l1/l2/U3' | +| `module_name` | Name of a new module that needs to be swapped in. | ## Example scripts diff --git a/src/odb/include/odb/db.h b/src/odb/include/odb/db.h index 634c07266b4..57f7e3773ea 100644 --- a/src/odb/include/odb/db.h +++ b/src/odb/include/odb/db.h @@ -8217,7 +8217,23 @@ class dbModule : public dbObject static dbModule* getModule(dbBlock* block_, uint dbid_); + // Copy and uniquify a given module based on current instance static dbModule* copy(dbModule* module, dbModInst* new_mod_inst); + static void copyModulePorts(dbModule* old_module, + dbModule* new_module, + modBTMap& mod_bt_map); + static void copyModuleInsts(dbModule* old_module, + dbModule* new_module, + dbModInst* new_mod_inst, + ITMap& it_map); + static void copyModuleModNets(dbModule* old_module, + dbModule* new_module, + modBTMap& mod_bt_map, + ITMap& it_map); + static void copyModuleBoundaryIO(dbModule* old_module, + dbModule* new_module, + dbModInst* new_mod_inst); + // User Code End dbModule }; diff --git a/src/odb/src/db/dbModule.cpp b/src/odb/src/db/dbModule.cpp index bb246be4fa9..5ab58640ff2 100644 --- a/src/odb/src/db/dbModule.cpp +++ b/src/odb/src/db/dbModule.cpp @@ -543,6 +543,10 @@ dbBlock* dbModule::getOwner() return (dbBlock*) obj->getOwner(); } +// Create a "deep" and unique copy of old_module based on +// its instance context. All ports, instances, mod nets and +// parent/child IO will be copied. Connections that span +// multiple modules needs to be done outside this API. dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) { dbBlock* block = old_module->getOwner(); @@ -568,23 +572,46 @@ dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) utl::ODB, 455, "Unique module {} cannot be created", new_cell_name); } - // copy module ports + // Copy module ports including bus members + modBTMap mod_bt_map; // map old mbterm to new mbterm + copyModulePorts(old_module, new_module, mod_bt_map); + + // Copy module instances and create iterm map + ITMap it_map; // map old iterm to new iterm + copyModuleInsts(old_module, new_module, new_mod_inst, it_map); + + // TODO: handle hierarchical child instances + + // Copy mod nets and connect ports and iterms + copyModuleModNets(old_module, new_module, mod_bt_map, it_map); + + // Establish boundary IO between parent and child + copyModuleBoundaryIO(old_module, new_module, new_mod_inst); + + return new_module; +} + +void dbModule::copyModulePorts(dbModule* old_module, + dbModule* new_module, + modBTMap& mod_bt_map) +{ + utl::Logger* logger = old_module->getImpl()->getLogger(); dbSet old_ports = old_module->getModBTerms(); dbSet::iterator port_iter; - std::map modBT_map; for (port_iter = old_ports.begin(); port_iter != old_ports.end(); ++port_iter) { dbModBTerm* old_port = *port_iter; dbModBTerm* new_port = dbModBTerm::create(new_module, old_port->getName()); - modBT_map[old_port] = new_port; + mod_bt_map[old_port] = new_port; new_port->setIoType(old_port->getIoType()); if (new_port) { debugPrint(logger, utl::ODB, "replace_design", 1, - "Created module port {}", - new_port->getName()); + "Created module port {} for old port {}", + new_port->getName(), + old_port->getName()); } else { logger->error(utl::ODB, 456, @@ -624,7 +651,7 @@ dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) dbModBTerm* old_bus_bit = old_bus_port->getBusIndexedElement(i); dbModBTerm* new_bus_bit = dbModBTerm::create(new_module, bus_bit_name.c_str()); - modBT_map[old_bus_bit] = new_bus_bit; + mod_bt_map[old_bus_bit] = new_bus_bit; if (new_bus_bit) { debugPrint(logger, utl::ODB, @@ -650,21 +677,33 @@ dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) } new_module->getModBTerms().reverse(); - // TODO: handle hierarchical child instances + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + "copyModulePorts: modBTMap has {} ports", + mod_bt_map.size()); +} +void dbModule::copyModuleInsts(dbModule* old_module, + dbModule* new_module, + dbModInst* new_mod_inst, + ITMap& it_map) +{ + utl::Logger* logger = old_module->getImpl()->getLogger(); // Add insts to new module dbSet old_insts = old_module->getInsts(); dbSet::iterator inst_iter; - std::map IT_map; for (inst_iter = old_insts.begin(); inst_iter != old_insts.end(); ++inst_iter) { dbInst* old_inst = *inst_iter; + // Change unique instance name from old_inst/leaf to new_inst/leaf std::string old_inst_name = old_inst->getName(); size_t first_idx = old_inst_name.find_first_of('/'); assert(first_idx != std::string::npos); - std::string old_relative_name = old_inst_name.substr(first_idx); - std::string new_inst_name = new_mod_inst->getName() + old_relative_name; - dbInst* new_inst = dbInst::create(block, + std::string old_leaf_name = old_inst_name.substr(first_idx); + std::string new_inst_name = new_mod_inst->getName() + old_leaf_name; + dbInst* new_inst = dbInst::create(old_module->getOwner(), old_inst->getMaster(), new_inst_name.c_str(), /* phyical only */ false, @@ -693,7 +732,7 @@ dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) ++iter1, ++iter2) { dbITerm* old_iterm = *iter1; dbITerm* new_iterm = *iter2; - IT_map[old_iterm] = new_iterm; + it_map[old_iterm] = new_iterm; debugPrint(logger, utl::ODB, "replace_design", @@ -709,7 +748,8 @@ dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) if (first_idx != std::string::npos) { std::string new_net_name = new_mod_inst->getName() + net_name.substr(first_idx); - dbNet* new_net = block->findNet(new_net_name.c_str()); + dbNet* new_net + = old_module->getOwner()->findNet(new_net_name.c_str()); if (new_net) { new_iterm->connect(new_net); debugPrint(logger, @@ -720,7 +760,8 @@ dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) new_iterm->getName(), new_net->getName()); } else { - new_net = dbNet::create(block, new_net_name.c_str()); + new_net + = dbNet::create(old_module->getOwner(), new_net_name.c_str()); new_iterm->connect(new_net); debugPrint(logger, utl::ODB, @@ -739,7 +780,21 @@ dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) && new_module->getInsts().orderReversed()) { new_module->getInsts().reverse(); } +} +void dbModule::copyModuleModNets(dbModule* old_module, + dbModule* new_module, + modBTMap& mod_bt_map, + ITMap& it_map) +{ + utl::Logger* logger = old_module->getImpl()->getLogger(); + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + "copyModuleModNets: modBT_map has {} ports, it_map has {} iterms", + mod_bt_map.size(), + it_map.size()); // Make boundary port connections. dbSet old_nets = old_module->getModNets(); dbSet::iterator net_iter; @@ -765,7 +820,7 @@ dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) dbSet::iterator mb_iter; for (mb_iter = mbterms.begin(); mb_iter != mbterms.end(); ++mb_iter) { dbModBTerm* old_mbterm = *mb_iter; - dbModBTerm* new_mbterm = modBT_map[old_mbterm]; + dbModBTerm* new_mbterm = mod_bt_map[old_mbterm]; if (new_mbterm) { new_mbterm->connect(new_net); debugPrint(logger, @@ -790,7 +845,7 @@ dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) dbSet::iterator it_iter; for (it_iter = iterms.begin(); it_iter != iterms.end(); ++it_iter) { dbITerm* old_iterm = *it_iter; - dbITerm* new_iterm = IT_map[old_iterm]; + dbITerm* new_iterm = it_map[old_iterm]; if (new_iterm) { new_iterm->connect(new_net); debugPrint(logger, @@ -810,7 +865,13 @@ dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) } } } +} +void dbModule::copyModuleBoundaryIO(dbModule* old_module, + dbModule* new_module, + dbModInst* new_mod_inst) +{ + utl::Logger* logger = old_module->getImpl()->getLogger(); // Establish "parent/child" port connections // dbModBTerm is the port seen from inside the dbModule ("child") // dbModITerm is the port seen from outside from the dbModInst ("parent") @@ -846,8 +907,6 @@ dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) old_mod_iterm->getName()); } } - - return new_module; } // User Code End dbModulePublicMethods From 2b448ddb903d0d2fa30b97052b5984991360adb9 Mon Sep 17 00:00:00 2001 From: Cho Moon Date: Fri, 15 Nov 2024 19:42:32 +0000 Subject: [PATCH 07/11] code review feedback from Andy Fox + clang-tidy fix Signed-off-by: Cho Moon --- src/odb/include/odb/odb.h | 5 +++++ src/odb/src/db/dbModInst.cpp | 22 +++++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/odb/include/odb/odb.h b/src/odb/include/odb/odb.h index b234e272cf2..3e0683bf0cf 100644 --- a/src/odb/include/odb/odb.h +++ b/src/odb/include/odb/odb.h @@ -54,4 +54,9 @@ using uint64 = std::uint64_t; using utl::format_as; #endif +class dbITerm; +class dbModBTerm; +using ITMap = std::map; +using modBTMap = std::map; + } // namespace odb diff --git a/src/odb/src/db/dbModInst.cpp b/src/odb/src/db/dbModInst.cpp index ef54dfd055e..cab50b24bc4 100644 --- a/src/odb/src/db/dbModInst.cpp +++ b/src/odb/src/db/dbModInst.cpp @@ -496,27 +496,39 @@ bool dbModInst::swapMaster(dbModule* new_module) for (it_iter = old_iterms.begin(); it_iter != old_iterms.end(); ++it_iter) { dbITerm* old_iterm = *it_iter; dbNet* flat_net = old_iterm->getNet(); + // iterm may be connected to another hierarchical instance, so save it + // before disconnecting + dbModNet* other_mod_net = old_iterm->getModNet(); old_iterm->disconnect(); debugPrint(logger, utl::ODB, "replace_design", 1, - " disconnected old iterm {} from flat net {} for mod net {}", + " disconnected old iterm {} from flat net {} + other mod net " + "{} for mod net {}", old_iterm->getName(), - flat_net->getName(), + (flat_net ? flat_net->getName() : "none"), + (other_mod_net ? other_mod_net->getName() : "none"), old_mod_net->getName()); dbSet::iterator new_it_iter; for (new_it_iter = new_iterms.begin(); new_it_iter != new_iterms.end(); ++new_it_iter) { dbITerm* new_iterm = *new_it_iter; - new_iterm->connect(flat_net); + if (flat_net) { + new_iterm->connect(flat_net); + } + if (other_mod_net) { + new_iterm->connect(other_mod_net); + } debugPrint(logger, utl::ODB, "replace_design", 1, - " connected new iterm {} to flat net {} for mod net {}", + " connected new iterm {} to flat net {} + other mod net {} " + "for mod net {}", new_iterm->getName(), - flat_net->getName(), + (flat_net ? flat_net->getName() : "none"), + (other_mod_net ? other_mod_net->getName() : "none"), old_mod_net->getName()); } } From f239bbe2a8e9bae2d2957416dbf3f11976ee52b5 Mon Sep 17 00:00:00 2001 From: Cho Moon Date: Fri, 15 Nov 2024 21:27:40 +0000 Subject: [PATCH 08/11] fixed regression failures Signed-off-by: Cho Moon --- .../test/report_cell_usage_modinsts_metrics.jsonok | 12 ++++++------ src/dbSta/test/report_cell_usage_modinsts_metrics.ok | 2 +- src/odb/src/db/dbModInst.cpp | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/dbSta/test/report_cell_usage_modinsts_metrics.jsonok b/src/dbSta/test/report_cell_usage_modinsts_metrics.jsonok index c734a141b3c..dbe3566a831 100644 --- a/src/dbSta/test/report_cell_usage_modinsts_metrics.jsonok +++ b/src/dbSta/test/report_cell_usage_modinsts_metrics.jsonok @@ -11,10 +11,10 @@ "design__instance__area__class:sequential_cell__in_module:block1": 1000, "design__instance__count__in_module:block1": 3, "design__instance__area__in_module:block1": 3000, - "design__instance__count__class:buffer__in_module:block1-1": 2, - "design__instance__area__class:buffer__in_module:block1-1": 2000, - "design__instance__count__class:sequential_cell__in_module:block1-1": 1, - "design__instance__area__class:sequential_cell__in_module:block1-1": 1000, - "design__instance__count__in_module:block1-1": 3, - "design__instance__area__in_module:block1-1": 3000 + "design__instance__count__class:buffer__in_module:block1.b2": 2, + "design__instance__area__class:buffer__in_module:block1.b2": 2000, + "design__instance__count__class:sequential_cell__in_module:block1.b2": 1, + "design__instance__area__class:sequential_cell__in_module:block1.b2": 1000, + "design__instance__count__in_module:block1.b2": 3, + "design__instance__area__in_module:block1.b2": 3000 } \ No newline at end of file diff --git a/src/dbSta/test/report_cell_usage_modinsts_metrics.ok b/src/dbSta/test/report_cell_usage_modinsts_metrics.ok index b713904d23a..f4f6ea581e3 100644 --- a/src/dbSta/test/report_cell_usage_modinsts_metrics.ok +++ b/src/dbSta/test/report_cell_usage_modinsts_metrics.ok @@ -16,7 +16,7 @@ Cell type report: Count Area Cell instance report: snl_bufx1 2 2000.00 snl_ffqx1 1 1000.00 -Cell type report for b2 (block1-1) +Cell type report for b2 (block1.b2) Cell type report: Count Area Buffer 2 2000.00 Sequential cell 1 1000.00 diff --git a/src/odb/src/db/dbModInst.cpp b/src/odb/src/db/dbModInst.cpp index cab50b24bc4..0f04af8f687 100644 --- a/src/odb/src/db/dbModInst.cpp +++ b/src/odb/src/db/dbModInst.cpp @@ -499,6 +499,9 @@ bool dbModInst::swapMaster(dbModule* new_module) // iterm may be connected to another hierarchical instance, so save it // before disconnecting dbModNet* other_mod_net = old_iterm->getModNet(); + if (other_mod_net == old_mod_net) { + other_mod_net = nullptr; + } old_iterm->disconnect(); debugPrint(logger, utl::ODB, From e276ae10db390b9ffe297149841807b9957bf12d Mon Sep 17 00:00:00 2001 From: Cho Moon Date: Sat, 16 Nov 2024 03:40:53 +0000 Subject: [PATCH 09/11] additional code re-architecture 1) shared makeUniqueDbModule between dbSta and db 2) changed module uniquification to use '_' instead of '.' 3) separated module uniquifcation and deep copy inside modInst::swapMaster() Signed-off-by: Cho Moon --- src/cts/test/simple_test_hier_out.vok | 28 ++++----- src/dbSta/src/dbReadVerilog.cc | 27 +------- src/dbSta/test/hierclock_out.vok | 4 +- src/dbSta/test/read_verilog10.ok | 2 +- src/dbSta/test/report_cell_usage_modinsts.ok | 2 +- .../report_cell_usage_modinsts_metrics.ok | 6 +- src/odb/include/odb/db.h | 9 ++- src/odb/src/db/dbModInst.cpp | 18 +++++- src/odb/src/db/dbModule.cpp | 62 ++++++++++--------- 9 files changed, 81 insertions(+), 77 deletions(-) diff --git a/src/cts/test/simple_test_hier_out.vok b/src/cts/test/simple_test_hier_out.vok index 325b9a12686..83be17fc49a 100644 --- a/src/cts/test/simple_test_hier_out.vok +++ b/src/cts/test/simple_test_hier_out.vok @@ -11,18 +11,18 @@ module test_16_sinks (clk); .Z(clknet_0_clk)); flop_pair U1 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair.U2 U2 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), + flop_pair_U2 U2 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair.U3 U3 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), + flop_pair_U3 U3 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair.U4 U4 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), + flop_pair_U4 U4 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair.U5 U5 (.clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair.U6 U6 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), + flop_pair_U5 U5 (.clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); + flop_pair_U6 U6 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair.U7 U7 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), + flop_pair_U7 U7 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); - flop_pair.U8 U8 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), + flop_pair_U8 U8 (.clknet_1_1__leaf_clk_i(clknet_1_1__leaf_clk), .clknet_1_0__leaf_clk_i(clknet_1_0__leaf_clk)); endmodule module flop_pair (clknet_1_1__leaf_clk_i, @@ -34,7 +34,7 @@ module flop_pair (clknet_1_1__leaf_clk_i, DFF_X1 ff1 (.CK(clknet_1_1__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_0__leaf_clk_i)); endmodule -module flop_pair.U2 (clknet_1_1__leaf_clk_i, +module flop_pair_U2 (clknet_1_1__leaf_clk_i, clknet_1_0__leaf_clk_i); input clknet_1_1__leaf_clk_i; input clknet_1_0__leaf_clk_i; @@ -43,7 +43,7 @@ module flop_pair.U2 (clknet_1_1__leaf_clk_i, DFF_X1 ff1 (.CK(clknet_1_1__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_0__leaf_clk_i)); endmodule -module flop_pair.U3 (clknet_1_1__leaf_clk_i, +module flop_pair_U3 (clknet_1_1__leaf_clk_i, clknet_1_0__leaf_clk_i); input clknet_1_1__leaf_clk_i; input clknet_1_0__leaf_clk_i; @@ -52,7 +52,7 @@ module flop_pair.U3 (clknet_1_1__leaf_clk_i, DFF_X1 ff1 (.CK(clknet_1_1__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_0__leaf_clk_i)); endmodule -module flop_pair.U4 (clknet_1_1__leaf_clk_i, +module flop_pair_U4 (clknet_1_1__leaf_clk_i, clknet_1_0__leaf_clk_i); input clknet_1_1__leaf_clk_i; input clknet_1_0__leaf_clk_i; @@ -61,14 +61,14 @@ module flop_pair.U4 (clknet_1_1__leaf_clk_i, DFF_X1 ff1 (.CK(clknet_1_0__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_1__leaf_clk_i)); endmodule -module flop_pair.U5 (clknet_1_0__leaf_clk_i); +module flop_pair_U5 (clknet_1_0__leaf_clk_i); input clknet_1_0__leaf_clk_i; DFF_X1 ff1 (.CK(clknet_1_0__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_0__leaf_clk_i)); endmodule -module flop_pair.U6 (clknet_1_1__leaf_clk_i, +module flop_pair_U6 (clknet_1_1__leaf_clk_i, clknet_1_0__leaf_clk_i); input clknet_1_1__leaf_clk_i; input clknet_1_0__leaf_clk_i; @@ -77,7 +77,7 @@ module flop_pair.U6 (clknet_1_1__leaf_clk_i, DFF_X1 ff1 (.CK(clknet_1_1__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_0__leaf_clk_i)); endmodule -module flop_pair.U7 (clknet_1_1__leaf_clk_i, +module flop_pair_U7 (clknet_1_1__leaf_clk_i, clknet_1_0__leaf_clk_i); input clknet_1_1__leaf_clk_i; input clknet_1_0__leaf_clk_i; @@ -86,7 +86,7 @@ module flop_pair.U7 (clknet_1_1__leaf_clk_i, DFF_X1 ff1 (.CK(clknet_1_0__leaf_clk_i)); DFF_X1 ff2 (.CK(clknet_1_1__leaf_clk_i)); endmodule -module flop_pair.U8 (clknet_1_1__leaf_clk_i, +module flop_pair_U8 (clknet_1_1__leaf_clk_i, clknet_1_0__leaf_clk_i); input clknet_1_1__leaf_clk_i; input clknet_1_0__leaf_clk_i; diff --git a/src/dbSta/src/dbReadVerilog.cc b/src/dbSta/src/dbReadVerilog.cc index 9056c666eb2..04de3b23bf3 100644 --- a/src/dbSta/src/dbReadVerilog.cc +++ b/src/dbSta/src/dbReadVerilog.cc @@ -179,7 +179,6 @@ class Verilog2db bool hasTerminals(Net* net) const; dbMaster* getMaster(Cell* cell); - dbModule* makeUniqueDbModule(Cell* cell, Instance* inst); std::optional parseLineInfo(const std::string& attribute); Network* network_; @@ -187,7 +186,6 @@ class Verilog2db dbBlock* block_ = nullptr; Logger* logger_; std::map master_map_; - std::map uniquify_id_; // key: module name // Map file names to a unique id to avoid having to store the full file name // for each instance std::map src_file_id_; @@ -293,28 +291,6 @@ void Verilog2db::recordBusPortsOrder() } } -dbModule* Verilog2db::makeUniqueDbModule(Cell* cell, Instance* inst) -{ - std::string orig_cell_name(network_->name(cell)); - dbModule* module = dbModule::create(block_, orig_cell_name.c_str()); - if (module != nullptr) { - return module; - } - - std::string module_name - = orig_cell_name + '.' + std::string(network_->name(inst)); - do { - std::string full_name = module_name; - int& id = uniquify_id_[module_name]; - if (id > 0) { - full_name += "_" + std::to_string(id); - } - ++id; - module = dbModule::create(block_, full_name.c_str()); - } while (module == nullptr); - return module; -} - std::optional Verilog2db::parseLineInfo( const std::string& attribute) { @@ -346,7 +322,8 @@ void Verilog2db::makeDbModule( module = block_->getTopModule(); } else { // This uniquifies the cell - module = makeUniqueDbModule(cell, inst); + module = dbModule::makeUniqueDbModule( + network_->name(cell), network_->name(inst), block_); // Strip out the full hiearchical name. We are now // storing the module instances in the scope of their diff --git a/src/dbSta/test/hierclock_out.vok b/src/dbSta/test/hierclock_out.vok index 6f3093a972a..6686b000a7c 100644 --- a/src/dbSta/test/hierclock_out.vok +++ b/src/dbSta/test/hierclock_out.vok @@ -36,7 +36,7 @@ module hierclock (a_count_valid_o, a_count_o[1], a_count_o[0]}), .count_valid_o(a_count_valid_o)); - counter.U3 U3 (.clk_i(clk2_int), + counter_U3 U3 (.clk_i(clk2_int), .rst_n_i(rst_n_i), .load_i(b_ld_i), .load_value_i({b_i[3], @@ -200,7 +200,7 @@ module counter (clk_i, .Q(counter_q[3]), .QN(\U2/_38_ )); endmodule -module counter.U3 (clk_i, +module counter_U3 (clk_i, rst_n_i, load_i, load_value_i, diff --git a/src/dbSta/test/read_verilog10.ok b/src/dbSta/test/read_verilog10.ok index 017da034dd3..09cea3b5a35 100644 --- a/src/dbSta/test/read_verilog10.ok +++ b/src/dbSta/test/read_verilog10.ok @@ -4,7 +4,7 @@ b1 block1 b1/r1 snl_ffqx1 b1/u1 snl_bufx1 b1/u2 snl_bufx1 -b2 block1.b2 +b2 block1_b2 b2/r1 snl_ffqx1 b2/u1 snl_bufx1 b2/u2 snl_bufx1 diff --git a/src/dbSta/test/report_cell_usage_modinsts.ok b/src/dbSta/test/report_cell_usage_modinsts.ok index 73f371f8059..963918703e5 100644 --- a/src/dbSta/test/report_cell_usage_modinsts.ok +++ b/src/dbSta/test/report_cell_usage_modinsts.ok @@ -16,7 +16,7 @@ Cell type report: Count Area Cell instance report: snl_bufx1 2 2000.00 snl_ffqx1 1 1000.00 -Cell type report for b2 (block1.b2) +Cell type report for b2 (block1_b2) Cell type report: Count Area Buffer 2 2000.00 Sequential cell 1 1000.00 diff --git a/src/dbSta/test/report_cell_usage_modinsts_metrics.ok b/src/dbSta/test/report_cell_usage_modinsts_metrics.ok index f4f6ea581e3..c29e019e9e4 100644 --- a/src/dbSta/test/report_cell_usage_modinsts_metrics.ok +++ b/src/dbSta/test/report_cell_usage_modinsts_metrics.ok @@ -16,7 +16,7 @@ Cell type report: Count Area Cell instance report: snl_bufx1 2 2000.00 snl_ffqx1 1 1000.00 -Cell type report for b2 (block1.b2) +Cell type report for b2 (block1_b2) Cell type report: Count Area Buffer 2 2000.00 Sequential cell 1 1000.00 @@ -25,4 +25,6 @@ Cell type report: Count Area Cell instance report: snl_bufx1 2 2000.00 snl_ffqx1 1 1000.00 -No differences found. +Differences found at line 14. + "design__instance__count__class:buffer__in_module:block1.b2": 2, + "design__instance__count__class:buffer__in_module:block1_b2": 2, diff --git a/src/odb/include/odb/db.h b/src/odb/include/odb/db.h index 57f7e3773ea..68e7d451812 100644 --- a/src/odb/include/odb/db.h +++ b/src/odb/include/odb/db.h @@ -8125,7 +8125,6 @@ class dbModInst : public dbObject /// Swap the module of this instance. /// Returns true if the operations succeeds. bool swapMaster(dbModule* module); - // User Code End dbModInst }; @@ -8217,8 +8216,14 @@ class dbModule : public dbObject static dbModule* getModule(dbBlock* block_, uint dbid_); + static dbModule* makeUniqueDbModule(const char* cell_name, + const char* inst_name, + dbBlock* block); + // Copy and uniquify a given module based on current instance - static dbModule* copy(dbModule* module, dbModInst* new_mod_inst); + static void copy(dbModule* module, + dbModule* module_copy, + dbModInst* new_mod_inst); static void copyModulePorts(dbModule* old_module, dbModule* new_module, modBTMap& mod_bt_map); diff --git a/src/odb/src/db/dbModInst.cpp b/src/odb/src/db/dbModInst.cpp index 0f04af8f687..86cb66dfcd9 100644 --- a/src/odb/src/db/dbModInst.cpp +++ b/src/odb/src/db/dbModInst.cpp @@ -480,7 +480,23 @@ bool dbModInst::swapMaster(dbModule* new_module) return false; } - _dbModule* new_master = (_dbModule*) dbModule::copy(new_module, this); + dbModule* new_module_copy = dbModule::makeUniqueDbModule( + new_module->getName(), this->getName(), getMaster()->getOwner()); + if (new_module_copy) { + debugPrint(logger, + utl::ODB, + "replace_design", + 1, + "Created uniquified module {}", + new_module_copy->getName()); + } else { + logger->error(utl::ODB, + 455, + "Unique module {} cannot be created", + new_module->getName()); + } + dbModule::copy(new_module, new_module_copy, this); + _dbModule* new_master = (_dbModule*) new_module_copy; // Patch connections such that boundary nets connect to new module iterms // instead of old module iterms diff --git a/src/odb/src/db/dbModule.cpp b/src/odb/src/db/dbModule.cpp index 5ab58640ff2..045cd8a0ee4 100644 --- a/src/odb/src/db/dbModule.cpp +++ b/src/odb/src/db/dbModule.cpp @@ -543,35 +543,41 @@ dbBlock* dbModule::getOwner() return (dbBlock*) obj->getOwner(); } -// Create a "deep" and unique copy of old_module based on -// its instance context. All ports, instances, mod nets and -// parent/child IO will be copied. Connections that span -// multiple modules needs to be done outside this API. -dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) -{ - dbBlock* block = old_module->getOwner(); - // Uniquify new module name as "module_name.inst_name" - std::string orig_cell_name(old_module->getName()); - size_t dot_index = orig_cell_name.find_first_of('.'); - if (dot_index != std::string::npos) { - orig_cell_name = orig_cell_name.substr(0, dot_index); - } - std::string new_cell_name - = orig_cell_name + '.' + std::string(new_mod_inst->getName()); - dbModule* new_module = create(block, new_cell_name.c_str()); - utl::Logger* logger = old_module->getImpl()->getLogger(); - if (new_module) { - debugPrint(logger, - utl::ODB, - "replace_design", - 1, - "Created uniquified module {}", - new_module->getName()); - } else { - logger->error( - utl::ODB, 455, "Unique module {} cannot be created", new_cell_name); +// Make a unique copy of module based on cell_name and inst_name +dbModule* dbModule::makeUniqueDbModule(const char* cell_name, + const char* inst_name, + dbBlock* block) + +{ + static std::map name_id_map; + dbModule* module = dbModule::create(block, cell_name); + if (module != nullptr) { + return module; } + std::string orig_cell_name(cell_name); + std::string module_name = orig_cell_name + '_' + std::string(inst_name); + do { + std::string full_name = module_name; + int& id = name_id_map[module_name]; + if (id > 0) { + full_name += "_" + std::to_string(id); + } + ++id; + module = dbModule::create(block, full_name.c_str()); + } while (module == nullptr); + return module; +} + +// Do a "deep" copy of old_module based on its instance context into new_module. +// All ports, instances, mod nets and parent/child IO will be copied. +// Connections that span multiple modules needs to be done outside this API. +// new_mod_inst is needed to create module instances for instance name +// uniquification. +void dbModule::copy(dbModule* old_module, + dbModule* new_module, + dbModInst* new_mod_inst) +{ // Copy module ports including bus members modBTMap mod_bt_map; // map old mbterm to new mbterm copyModulePorts(old_module, new_module, mod_bt_map); @@ -587,8 +593,6 @@ dbModule* dbModule::copy(dbModule* old_module, dbModInst* new_mod_inst) // Establish boundary IO between parent and child copyModuleBoundaryIO(old_module, new_module, new_mod_inst); - - return new_module; } void dbModule::copyModulePorts(dbModule* old_module, From 9856197f553043442ba5be2303b640e738e28911 Mon Sep 17 00:00:00 2001 From: Cho Moon Date: Tue, 19 Nov 2024 03:45:10 +0000 Subject: [PATCH 10/11] minor clang-tidy fix Signed-off-by: Cho Moon --- src/odb/include/odb/db.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/odb/include/odb/db.h b/src/odb/include/odb/db.h index 68e7d451812..29952c73888 100644 --- a/src/odb/include/odb/db.h +++ b/src/odb/include/odb/db.h @@ -8221,8 +8221,8 @@ class dbModule : public dbObject dbBlock* block); // Copy and uniquify a given module based on current instance - static void copy(dbModule* module, - dbModule* module_copy, + static void copy(dbModule* old_module, + dbModule* new_copy, dbModInst* new_mod_inst); static void copyModulePorts(dbModule* old_module, dbModule* new_module, From 2b9cb357e8b92912d98c8fd45893bb5fe2afdf0e Mon Sep 17 00:00:00 2001 From: Cho Moon Date: Tue, 19 Nov 2024 03:56:05 +0000 Subject: [PATCH 11/11] clang-tidy fix part 2 Signed-off-by: Cho Moon --- src/odb/include/odb/db.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odb/include/odb/db.h b/src/odb/include/odb/db.h index 29952c73888..b2f971820f7 100644 --- a/src/odb/include/odb/db.h +++ b/src/odb/include/odb/db.h @@ -8222,7 +8222,7 @@ class dbModule : public dbObject // Copy and uniquify a given module based on current instance static void copy(dbModule* old_module, - dbModule* new_copy, + dbModule* new_module, dbModInst* new_mod_inst); static void copyModulePorts(dbModule* old_module, dbModule* new_module,