@@ -8954,45 +8954,97 @@ namespace phy_engine::verilog::digital
89548954 out_index.reserve(gate_count * 2u + 8u);
89558955 bool ok2{true};
89568956
8957- auto dfs2 = [&](auto&& self, ::phy_engine::model::node_t* n) noexcept -> ::std::uint8_t
8958- {
8959- if(!ok2 || n == nullptr)
8960- {
8961- ok2 = false;
8962- return 254u;
8963- }
8964- if(auto itc = const_idx.find(n); itc != const_idx.end()) { return itc->second; }
8965- if(auto itl = leaf_index.find(n); itl != leaf_index.end()) { return itl->second; }
8966- if(auto ito = out_index.find(n); ito != out_index.end()) { return ito->second; }
8967-
8968- auto itg = gate_by_out.find(n);
8969- if(itg == gate_by_out.end())
8970- {
8971- ok2 = false;
8972- return 254u;
8973- }
8974- auto const& gg = itg->second;
8975-
8976- auto const a = self(self, gg.in0);
8977- auto const b = (gg.k == kind::not_gate) ? static_cast<::std::uint8_t>(254u) : self(self, gg.in1);
8978- if(!ok2) { return 254u; }
8979-
8980- if(cone.gate_count >= 64u)
8981- {
8982- ok2 = false;
8983- return 254u;
8984- }
8985- auto const gi = static_cast<::std::uint8_t>(cone.gate_count++);
8986- cone.kind[gi] = enc_kind(gg.k);
8987- cone.in0[gi] = a;
8988- cone.in1[gi] = b;
8989- auto const out = static_cast<::std::uint8_t>(6u + gi);
8990- out_index.emplace(n, out);
8991- return out;
8992- };
8993-
8994- (void)dfs2(dfs2, root);
8995- if(!ok2 || cone.gate_count == 0u) { continue; }
8957+ // Build a u64 cone in topological order (iterative; cycle-safe).
8958+ auto idx_of = [&](::phy_engine::model::node_t* n) noexcept -> ::std::optional<::std::uint8_t>
8959+ {
8960+ if(n == nullptr) { return ::std::nullopt; }
8961+ if(auto itc = const_idx.find(n); itc != const_idx.end()) { return itc->second; }
8962+ if(auto itl = leaf_index.find(n); itl != leaf_index.end()) { return itl->second; }
8963+ if(auto ito = out_index.find(n); ito != out_index.end()) { return ito->second; }
8964+ return ::std::nullopt;
8965+ };
8966+
8967+ struct frame
8968+ {
8969+ ::phy_engine::model::node_t* n{};
8970+ bool expanded{};
8971+ };
8972+
8973+ ::std::unordered_map<::phy_engine::model::node_t*, bool> visiting{};
8974+ visiting.reserve(gate_count * 2u + 8u);
8975+
8976+ ::std::vector<frame> st{};
8977+ st.reserve(128);
8978+ st.push_back(frame{root, false});
8979+ while(!st.empty())
8980+ {
8981+ if(!ok2) { break; }
8982+ auto& f = st.back();
8983+ auto* n = f.n;
8984+ if(n == nullptr)
8985+ {
8986+ ok2 = false;
8987+ break;
8988+ }
8989+ if(idx_of(n).has_value())
8990+ {
8991+ st.pop_back();
8992+ continue;
8993+ }
8994+ auto itg = gate_by_out.find(n);
8995+ if(itg == gate_by_out.end())
8996+ {
8997+ ok2 = false;
8998+ break;
8999+ }
9000+ auto const& gg = itg->second;
9001+
9002+ if(!f.expanded)
9003+ {
9004+ if(visiting.contains(n))
9005+ {
9006+ // Combinational loop inside the gate graph.
9007+ ok2 = false;
9008+ break;
9009+ }
9010+ visiting.emplace(n, true);
9011+ f.expanded = true;
9012+
9013+ // Post-order: push children first.
9014+ if(gg.k != kind::not_gate)
9015+ {
9016+ if(!idx_of(gg.in1).has_value()) { st.push_back(frame{gg.in1, false}); }
9017+ }
9018+ if(!idx_of(gg.in0).has_value()) { st.push_back(frame{gg.in0, false}); }
9019+ continue;
9020+ }
9021+
9022+ auto a = idx_of(gg.in0);
9023+ if(!a) { ok2 = false; break; }
9024+ ::std::optional<::std::uint8_t> b{};
9025+ if(gg.k == kind::not_gate) { b = static_cast<::std::uint8_t>(254u); }
9026+ else
9027+ {
9028+ b = idx_of(gg.in1);
9029+ }
9030+ if(!b) { ok2 = false; break; }
9031+
9032+ if(cone.gate_count >= 64u)
9033+ {
9034+ ok2 = false;
9035+ break;
9036+ }
9037+ auto const gi = static_cast<::std::uint8_t>(cone.gate_count++);
9038+ cone.kind[gi] = enc_kind(gg.k);
9039+ cone.in0[gi] = *a;
9040+ cone.in1[gi] = *b;
9041+ auto const out = static_cast<::std::uint8_t>(6u + gi);
9042+ out_index.emplace(n, out);
9043+ visiting.erase(n);
9044+ st.pop_back();
9045+ }
9046+
9047+ if(!ok2 || cone.gate_count == 0u) { continue; }
89969048
89979049 cd.leaves = ::std::move(leaves);
89989050 cd.cone = cone;
@@ -9857,45 +9909,95 @@ namespace phy_engine::verilog::digital
98579909 out_index.reserve(gate_count * 2u + 8u);
98589910 bool ok2{true};
98599911
9860- auto dfs2 = [&](auto&& self, ::phy_engine::model::node_t* n) noexcept -> ::std::uint8_t
9861- {
9862- if(!ok2 || n == nullptr)
9863- {
9864- ok2 = false;
9865- return 254u;
9866- }
9867- if(auto itc = const_idx.find(n); itc != const_idx.end()) { return itc->second; }
9868- if(auto itl = leaf_index.find(n); itl != leaf_index.end()) { return itl->second; }
9869- if(auto ito = out_index.find(n); ito != out_index.end()) { return ito->second; }
9870-
9871- auto itg = gate_by_out.find(n);
9872- if(itg == gate_by_out.end())
9873- {
9874- ok2 = false;
9875- return 254u;
9876- }
9877- auto const& gg = itg->second;
9878-
9879- auto const a = self(self, gg.in0);
9880- auto const b = (gg.k == kind::not_gate) ? static_cast<::std::uint8_t>(254u) : self(self, gg.in1);
9881- if(!ok2) { return 254u; }
9882-
9883- if(cone.gate_count >= 64u)
9884- {
9885- ok2 = false;
9886- return 254u;
9887- }
9888- auto const gi = static_cast<::std::uint8_t>(cone.gate_count++);
9889- cone.kind[gi] = enc_kind(gg.k);
9890- cone.in0[gi] = a;
9891- cone.in1[gi] = b;
9892- auto const out = static_cast<::std::uint8_t>(6u + gi);
9893- out_index.emplace(n, out);
9894- return out;
9895- };
9896-
9897- (void)dfs2(dfs2, root);
9898- if(!ok2 || cone.gate_count == 0u) { continue; }
9912+ // Build a u64 cone in topological order (iterative; cycle-safe).
9913+ auto idx_of = [&](::phy_engine::model::node_t* n) noexcept -> ::std::optional<::std::uint8_t>
9914+ {
9915+ if(n == nullptr) { return ::std::nullopt; }
9916+ if(auto itc = const_idx.find(n); itc != const_idx.end()) { return itc->second; }
9917+ if(auto itl = leaf_index.find(n); itl != leaf_index.end()) { return itl->second; }
9918+ if(auto ito = out_index.find(n); ito != out_index.end()) { return ito->second; }
9919+ return ::std::nullopt;
9920+ };
9921+
9922+ struct frame
9923+ {
9924+ ::phy_engine::model::node_t* n{};
9925+ bool expanded{};
9926+ };
9927+
9928+ ::std::unordered_map<::phy_engine::model::node_t*, bool> visiting{};
9929+ visiting.reserve(gate_count * 2u + 8u);
9930+
9931+ ::std::vector<frame> st{};
9932+ st.reserve(128);
9933+ st.push_back(frame{root, false});
9934+ while(!st.empty())
9935+ {
9936+ if(!ok2) { break; }
9937+ auto& f = st.back();
9938+ auto* n = f.n;
9939+ if(n == nullptr)
9940+ {
9941+ ok2 = false;
9942+ break;
9943+ }
9944+ if(idx_of(n).has_value())
9945+ {
9946+ st.pop_back();
9947+ continue;
9948+ }
9949+ auto itg = gate_by_out.find(n);
9950+ if(itg == gate_by_out.end())
9951+ {
9952+ ok2 = false;
9953+ break;
9954+ }
9955+ auto const& gg = itg->second;
9956+
9957+ if(!f.expanded)
9958+ {
9959+ if(visiting.contains(n))
9960+ {
9961+ ok2 = false;
9962+ break;
9963+ }
9964+ visiting.emplace(n, true);
9965+ f.expanded = true;
9966+
9967+ if(gg.k != kind::not_gate)
9968+ {
9969+ if(!idx_of(gg.in1).has_value()) { st.push_back(frame{gg.in1, false}); }
9970+ }
9971+ if(!idx_of(gg.in0).has_value()) { st.push_back(frame{gg.in0, false}); }
9972+ continue;
9973+ }
9974+
9975+ auto a = idx_of(gg.in0);
9976+ if(!a) { ok2 = false; break; }
9977+ ::std::optional<::std::uint8_t> b{};
9978+ if(gg.k == kind::not_gate) { b = static_cast<::std::uint8_t>(254u); }
9979+ else
9980+ {
9981+ b = idx_of(gg.in1);
9982+ }
9983+ if(!b) { ok2 = false; break; }
9984+
9985+ if(cone.gate_count >= 64u)
9986+ {
9987+ ok2 = false;
9988+ break;
9989+ }
9990+ auto const gi = static_cast<::std::uint8_t>(cone.gate_count++);
9991+ cone.kind[gi] = enc_kind(gg.k);
9992+ cone.in0[gi] = *a;
9993+ cone.in1[gi] = *b;
9994+ auto const out = static_cast<::std::uint8_t>(6u + gi);
9995+ out_index.emplace(n, out);
9996+ visiting.erase(n);
9997+ st.pop_back();
9998+ }
9999+
10000+ if(!ok2 || cone.gate_count == 0u) { continue; }
989910001
990010002 cd.leaves = ::std::move(leaves);
990110003 cd.cone = cone;
0 commit comments