Major additions, all wired end-to-end with doctest coverage:
- Altium netlist importer (`imports/import_altium.{hpp,cpp}`): two-pass
parser for `[ ]` parts and `( )` signals; `System::Load` no longer has
the IMPORT_ALTIUM hole.
- `duplicate <src> <dst>` deep-copies a module (signals, parts, pins,
rewired signals); connections excluded by design.
- Nets (`system/nets.{hpp,cpp}`): BFS over `Connection::pin_map` to
return the transitive (Module, Signal) closure. `verify` extended with
a second pass flagging Power↔GndShield inconsistencies in bridged
nets; new `net <module> <signal>` command for inspection.
- Canonical pin names (`system/pin_name.{hpp,cpp}`): zero-padded digit
suffix lets A1 ↔ A001 pair via `IdentityTransform` and
`CheckIdentityCompatible` without losing the imported notation.
- Component classification (`system/component_kind.{hpp,cpp}`):
`Part::kind` inferred at construction from the reference-designator
prefix (longest-match: LED/TP/SW/FB/MK/MP/MH/HS/RA/RN/RP/RV first,
then R/C/L/F/D/Q/U/J/P/Y/X/S).
- Identity wiring tolerance: `CheckIdentityCompatible` accepts the
subset case (typical when one importer drops NC pins, e.g. Altium)
and surfaces orphans as an info string. `FillIdentityNCs`
materialises orphan canonical positions as NC pins on the missing
side at connect time.
- Connector layout preparation: `pin_layout(kind)` and
`FillPartFromLayout(part, kind)` stubs in `pin_role`, called from
`set-type`. Empty today; populate alongside `vpx_3u_role`.
- TUI scrollback: PageUp/PageDown step 10 lines, Home/End jump to
ends; `Print()` snaps back to the tail.
- `set <name> <value>` declares session variables; `$name` / `${name}`
expanded inside `Finalize` between canonical-form recording and the
action call — history and script-save preserve `$var` references.
- Long `source` scripts now show a centred "Computing…" modal with a
N/M progress counter. Driven by a ticker thread that posts one
paced `Event::Special` per processed line, ack'd by the main thread,
so heavy lines don't backlog ticks and freeze the counter.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
118 lines
3.5 KiB
C++
118 lines
3.5 KiB
C++
#include "system/nets.hpp"
|
|
|
|
#include "system/connect.hpp"
|
|
#include "system/modules.hpp"
|
|
#include "system/parts.hpp"
|
|
#include "system/pins.hpp"
|
|
#include "system/signals.hpp"
|
|
#include "system/system.hpp"
|
|
|
|
#include <queue>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
|
|
namespace {
|
|
|
|
using SigKey = std::pair<Module *, Signal *>;
|
|
|
|
struct SigKeyHash {
|
|
size_t operator()(const SigKey &k) const noexcept {
|
|
return std::hash<void *>()(k.first) ^ (std::hash<void *>()(k.second) << 1);
|
|
}
|
|
};
|
|
|
|
std::unordered_map<Pin *, std::vector<Pin *>>
|
|
build_bridges(System *sys) {
|
|
std::unordered_map<Pin *, std::vector<Pin *>> br;
|
|
if (!sys || !sys->connections()) return br;
|
|
for (auto &kv : *sys->connections()) {
|
|
for (auto &wp : kv.second->pin_map) {
|
|
br[wp.first].push_back(wp.second);
|
|
br[wp.second].push_back(wp.first);
|
|
}
|
|
}
|
|
return br;
|
|
}
|
|
|
|
void bfs_net(const std::unordered_map<Pin *, std::vector<Pin *>> &bridges,
|
|
Module *start_m, Signal *start_s,
|
|
std::unordered_set<SigKey, SigKeyHash> &visited,
|
|
Net &out) {
|
|
if (!start_m || !start_s) return;
|
|
SigKey start{start_m, start_s};
|
|
if (!visited.insert(start).second) return;
|
|
std::queue<SigKey> q;
|
|
q.push(start);
|
|
while (!q.empty()) {
|
|
auto [m, s] = q.front();
|
|
q.pop();
|
|
out.members.emplace_back(m, s);
|
|
for (auto &pkv : *s) {
|
|
auto it = bridges.find(pkv.second);
|
|
if (it == bridges.end()) continue;
|
|
for (Pin *other : it->second) {
|
|
Signal *os = other->signal();
|
|
if (!os) continue;
|
|
Part *opart = other->prnt;
|
|
if (!opart) continue;
|
|
Module *om = opart->prnt;
|
|
if (!om) continue;
|
|
SigKey k{om, os};
|
|
if (visited.insert(k).second) q.push(k);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
Net find_net(System *sys, Module *m, Signal *s) {
|
|
Net n;
|
|
if (!sys || !m || !s) return n;
|
|
auto bridges = build_bridges(sys);
|
|
std::unordered_set<SigKey, SigKeyHash> visited;
|
|
bfs_net(bridges, m, s, visited, n);
|
|
return n;
|
|
}
|
|
|
|
Net find_net(System *sys, Pin *pin) {
|
|
if (!sys || !pin || !pin->signal() || !pin->prnt) return {};
|
|
return find_net(sys, pin->prnt->prnt, pin->signal());
|
|
}
|
|
|
|
std::vector<Net> compute_all_nets(System *sys) {
|
|
std::vector<Net> nets;
|
|
if (!sys || !sys->modules()) return nets;
|
|
auto bridges = build_bridges(sys);
|
|
std::unordered_set<SigKey, SigKeyHash> visited;
|
|
for (auto &mkv : *sys->modules()) {
|
|
Module *m = mkv.second;
|
|
if (!m->signals) continue;
|
|
for (auto &skv : *m->signals) {
|
|
SigKey k{m, skv.second};
|
|
if (visited.count(k)) continue;
|
|
Net n;
|
|
bfs_net(bridges, m, skv.second, visited, n);
|
|
if (!n.members.empty()) nets.push_back(std::move(n));
|
|
}
|
|
}
|
|
return nets;
|
|
}
|
|
|
|
bool net_type_consistent(const Net &net, SignalType &dominant) {
|
|
bool seen_power = false, seen_gnd = false;
|
|
for (auto &mp : net.members) {
|
|
if (!mp.second) continue;
|
|
switch (mp.second->type) {
|
|
case SignalType::Power: seen_power = true; break;
|
|
case SignalType::GndShield: seen_gnd = true; break;
|
|
default: break;
|
|
}
|
|
}
|
|
if (seen_power && seen_gnd) { dominant = SignalType::Power; return false; }
|
|
dominant = seen_power ? SignalType::Power
|
|
: seen_gnd ? SignalType::GndShield
|
|
: SignalType::Other;
|
|
return true;
|
|
}
|