From fa257a5d9129d2545adc408bae0a3584d697d262 Mon Sep 17 00:00:00 2001 From: Lukas K Date: Fri, 14 Jan 2022 01:17:37 +0100 Subject: [PATCH] add more schematic checks - one-label nets - unconnected pins - unconnected ports --- src/imp/rules/rule_editor_connectivity.cpp | 50 ++++++-- src/schematic/schematic_rules_check.cpp | 131 +++++++++++++++++++++ src/schematic/sheet.cpp | 6 + src/schematic/sheet.hpp | 2 + 4 files changed, 180 insertions(+), 9 deletions(-) diff --git a/src/imp/rules/rule_editor_connectivity.cpp b/src/imp/rules/rule_editor_connectivity.cpp index eec84e6e2..d8ec67460 100644 --- a/src/imp/rules/rule_editor_connectivity.cpp +++ b/src/imp/rules/rule_editor_connectivity.cpp @@ -6,14 +6,46 @@ void RuleEditorConnectivity::populate() { rule2 = &dynamic_cast(rule); - Gtk::CheckButton *editor = Gtk::manage(new Gtk::CheckButton("Include unnamed nets")); - editor->set_valign(Gtk::ALIGN_START); - pack_start(*editor, true, true, 0); - editor->set_active(rule2->include_unnamed); - editor->signal_toggled().connect([this, editor] { - rule2->include_unnamed = editor->get_active(); - s_signal_updated.emit(); - }); - editor->show(); + auto box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); + box->set_margin_start(20); + box->set_margin_end(20); + box->set_margin_bottom(20); + { + auto la = Gtk::manage(new Gtk::Label("• One-pin nets")); + la->set_halign(Gtk::ALIGN_START); + box->pack_start(*la, true, true, 0); + } + { + Gtk::CheckButton *editor = Gtk::manage(new Gtk::CheckButton("Include unnamed nets")); + editor->set_halign(Gtk::ALIGN_START); + editor->set_margin_start(10); + box->pack_start(*editor, true, true, 0); + editor->set_active(rule2->include_unnamed); + editor->signal_toggled().connect([this, editor] { + rule2->include_unnamed = editor->get_active(); + s_signal_updated.emit(); + }); + } + { + auto la = Gtk::manage(new Gtk::Label("• One-label nets")); + la->set_margin_top(5); + la->set_halign(Gtk::ALIGN_START); + box->pack_start(*la, true, true, 0); + } + { + auto la = Gtk::manage(new Gtk::Label("• Unconnected pins")); + la->set_margin_top(5); + la->set_halign(Gtk::ALIGN_START); + box->pack_start(*la, true, true, 0); + } + { + auto la = Gtk::manage(new Gtk::Label("• Unconnected ports")); + la->set_margin_top(5); + la->set_halign(Gtk::ALIGN_START); + box->pack_start(*la, true, true, 0); + } + + box->show_all(); + pack_start(*box, false, false, 0); } } // namespace horizon diff --git a/src/schematic/schematic_rules_check.cpp b/src/schematic/schematic_rules_check.cpp index 2cd0c6742..e058eee87 100644 --- a/src/schematic/schematic_rules_check.cpp +++ b/src/schematic/schematic_rules_check.cpp @@ -34,6 +34,137 @@ RulesCheckResult SchematicRules::check_connectivity(const BlocksSchematic &block } } } + const auto all_sheets = blocks.get_top_block_item().schematic.get_all_sheets(); + + + for (const auto &[uu_block, block_item] : blocks.blocks) { + std::map> net_segments_with_labels; + for (const auto &[uu_sheet, sheet] : block_item.schematic.sheets) { + auto net_segments = sheet.analyze_net_segments(); + for (const auto &[ns, nsinfo] : net_segments) { + if (nsinfo.really_has_label()) { + if (!nsinfo.net->is_port) + net_segments_with_labels[nsinfo.net->uuid].insert(ns); + } + } + } + for (const auto &[net, net_segments] : net_segments_with_labels) { + if (net_segments.size() == 1) { + const auto seg = *net_segments.begin(); + r.errors.emplace_back(RulesCheckErrorLevel::WARN); + auto &x = r.errors.back(); + x.comment = "Net \"" + block_item.block.get_net_name(net) + "\" only has one net segment with a label"; + // find sheet the only label is on + bool found = false; + for (const auto &[uu_sheet, sheet] : block_item.schematic.sheets) { + for (const auto &[uu_label, label] : sheet.net_labels) { + if (label.junction->net->uuid == net && label.junction->net_segment == seg) { + // find first sheet to place warning on + for (const auto &it : all_sheets) { + if (it.schematic.block->uuid == uu_block && it.sheet.uuid == uu_sheet) { + x.has_location = true; + if (it.instance_path.size()) + x.comment += " (Only shown in first instance)"; + x.instance_path = it.instance_path; + x.sheet = it.sheet.uuid; + x.location = label.junction->position; + break; + } + } + + found = true; + break; + } + } + if (found) + break; + } + } + } + } + + for (const auto &[uu_block, block_item] : blocks.blocks) { + for (const auto &[uu_comp, comp] : block_item.block.components) { + std::set> pins; + for (const auto &[uu_gate, gate] : comp.entity->gates) { + for (const auto &[uu_pin, pin] : gate.unit->pins) { + pins.emplace(uu_gate, uu_pin); + } + } + for (const auto &[path, net] : comp.connections) + pins.erase(path); + + for (const auto &pin_path : pins) { + r.errors.emplace_back(RulesCheckErrorLevel::FAIL); + auto &x = r.errors.back(); + const auto &gate = comp.entity->gates.at(pin_path.at(0)); + x.comment = "Pin " + comp.refdes + gate.suffix + "." + gate.unit->pins.at(pin_path.at(1)).primary_name + + " is not connected (not found in schematic)"; + bool found = false; + for (const auto &it : all_sheets) { + for (const auto &[uu_sym, sym] : it.sheet.symbols) { + if (sym.component->uuid == uu_comp && sym.gate->uuid == pin_path.at(0)) { + x.comment = "Pin " + + blocks.get_top_block_item() + .block.get_component_info(comp, it.instance_path) + .refdes + + sym.gate->suffix + "." + sym.gate->unit->pins.at(pin_path.at(1)).primary_name + + " is not connected"; + x.has_location = true; + if (it.instance_path.size()) + x.comment += " (Only shown in first instance)"; + x.instance_path = it.instance_path; + x.sheet = it.sheet.uuid; + x.location = sym.placement.transform(sym.symbol.pins.at(pin_path.at(1)).position); + found = true; + break; + } + } + if (found) + break; + } + } + } + } + + for (const auto &[uu_block, block_item] : blocks.blocks) { + for (const auto &[uu_inst, inst] : block_item.block.block_instances) { + std::set ports; + for (const auto &[uu_net, net] : inst.block->nets) { + if (net.is_port) + ports.insert(uu_net); + } + for (const auto &[uu_port, conn] : inst.connections) + ports.erase(uu_port); + + for (const auto &uu_port : ports) { + r.errors.emplace_back(RulesCheckErrorLevel::FAIL); + auto &x = r.errors.back(); + x.comment = "Port " + inst.refdes + "." + inst.block->nets.at(uu_port).name + " is not connected"; + bool found = false; + for (const auto &it : all_sheets) { + for (const auto &[uu_sym, sym] : it.sheet.block_symbols) { + if (sym.block_instance->uuid == uu_inst) { + x.has_location = true; + if (it.instance_path.size()) + x.comment += " (Only shown in first instance)"; + x.instance_path = it.instance_path; + x.sheet = it.sheet.uuid; + x.location = sym.placement.transform( + sym.symbol.ports.at(BlockSymbolPort::get_uuid_for_net(uu_port)).position); + found = true; + break; + } + } + if (found) + break; + } + if (!found) + x.comment += " (Not found on schematic)"; + } + } + } + r.update(); return r; } diff --git a/src/schematic/sheet.cpp b/src/schematic/sheet.cpp index 47397dd3d..f127ad5f2 100644 --- a/src/schematic/sheet.cpp +++ b/src/schematic/sheet.cpp @@ -526,6 +526,11 @@ bool NetSegmentInfo::is_bus() const return false; } +bool NetSegmentInfo::really_has_label() const +{ + return has_label && !has_power_sym && !has_bus_ripper; +} + std::map Sheet::analyze_net_segments() const { std::map net_segments; @@ -551,6 +556,7 @@ std::map Sheet::analyze_net_segments() const for (const auto &it : bus_rippers) { if (net_segments.count(it.second.net_segment)) { net_segments.at(it.second.net_segment).has_label = true; + net_segments.at(it.second.net_segment).has_bus_ripper = true; } } diff --git a/src/schematic/sheet.hpp b/src/schematic/sheet.hpp index 916c53ccf..72ab81663 100644 --- a/src/schematic/sheet.hpp +++ b/src/schematic/sheet.hpp @@ -31,6 +31,8 @@ class NetSegmentInfo { NetSegmentInfo(const SchematicJunction *ju); bool has_label = false; bool has_power_sym = false; + bool has_bus_ripper = false; + bool really_has_label() const; Coordi position; Net *net = nullptr; Bus *bus = nullptr;