@@ -575,6 +575,13 @@ bool DbInstanceNetIterator::hasNext()
575575 if (chip_walk_) {
576576 return chip_net_iter_ != chip_net_end_;
577577 }
578+ // 3DIC mode: only the top-instance chip-net walk (chip_walk_) is valid.
579+ // For any other instance the ctor returns early and the legacy iter_/end_
580+ // members are left default-constructed, so report empty instead of
581+ // comparing them (default-constructed dbSet iterators are UB to compare).
582+ if (network_->has3DicChip ()) {
583+ return false ;
584+ }
578585 if (network_->hasHierarchy ()) {
579586 if (mod_net_iter_ != mod_net_end_) {
580587 return true ;
@@ -594,6 +601,10 @@ Net* DbInstanceNetIterator::next()
594601 }
595602 return nullptr ;
596603 }
604+ // 3DIC, non-top instance: empty (see hasNext) — never touch iter_.
605+ if (network_->has3DicChip ()) {
606+ return nullptr ;
607+ }
597608 if (network_->hasHierarchy ()) {
598609 if (mod_net_iter_ != mod_net_end_) {
599610 odb::dbModNet* net = *mod_net_iter_;
@@ -1868,7 +1879,13 @@ ObjectId dbNetwork::id(const Pin* pin) const
18681879
18691880 staToDb (pin, iterm, bterm, moditerm);
18701881
1871- if (hasHierarchy ()) {
1882+ // In 3DIC mode every chiplet block numbers its own iterms/bterms from 1,
1883+ // so the raw-id branch below collides across blocks. Route inner pins
1884+ // through the tagged encoder (which mixes the block id in via
1885+ // blockDiscBits) so PinSet/visited_pins dedup stays correct when
1886+ // visitConnectedPins descends into multiple chiplet inner nets — the
1887+ // pin-side counterpart of the id(Net*) discriminator.
1888+ if (hasHierarchy () || has3DicChip ()) {
18721889 // get the id for hierarchical objects using dbid.
18731890 std::uintptr_t tag_value
18741891 = reinterpret_cast <std::uintptr_t >(pin) & kPointerTagMask ;
0 commit comments