Fixed: Fewer ERC items for pin connection conflicts in larger set of conflicting pins

This commit is contained in:
Daniel Treffenstädt 2024-11-22 23:26:31 +00:00 committed by Wayne Stambaugh
parent 9e7ffc6ff0
commit 81ecccb21c
8 changed files with 2434 additions and 17 deletions

View File

@ -51,6 +51,7 @@
#include <symbol_lib_table.h> #include <symbol_lib_table.h>
#include <drawing_sheet/ds_draw_item.h> #include <drawing_sheet/ds_draw_item.h>
#include <drawing_sheet/ds_proxy_view_item.h> #include <drawing_sheet/ds_proxy_view_item.h>
#include <vector>
#include <wx/ffile.h> #include <wx/ffile.h>
#include <sim/sim_lib_mgr.h> #include <sim/sim_lib_mgr.h>
#include <progress_reporter.h> #include <progress_reporter.h>
@ -888,6 +889,7 @@ int ERC_TESTER::TestPinToPin()
for( const std::pair<NET_NAME_CODE_CACHE_KEY, std::vector<CONNECTION_SUBGRAPH*>> net : m_nets ) for( const std::pair<NET_NAME_CODE_CACHE_KEY, std::vector<CONNECTION_SUBGRAPH*>> net : m_nets )
{ {
using iterator_t = std::vector<ERC_SCH_PIN_CONTEXT>::iterator;
std::vector<ERC_SCH_PIN_CONTEXT> pins; std::vector<ERC_SCH_PIN_CONTEXT> pins;
std::unordered_map<EDA_ITEM*, SCH_SCREEN*> pinToScreenMap; std::unordered_map<EDA_ITEM*, SCH_SCREEN*> pinToScreenMap;
bool has_noconnect = false; bool has_noconnect = false;
@ -940,6 +942,9 @@ int ERC_TESTER::TestPinToPin()
} }
} }
std::vector<std::tuple<iterator_t, iterator_t, PIN_ERROR>> pin_mismatches;
std::map<iterator_t, int> pin_mismatch_counts;
for( auto refIt = pins.begin(); refIt != pins.end(); ++refIt ) for( auto refIt = pins.begin(); refIt != pins.end(); ++refIt )
{ {
ERC_SCH_PIN_CONTEXT& refPin = *refIt; ERC_SCH_PIN_CONTEXT& refPin = *refIt;
@ -986,24 +991,111 @@ int ERC_TESTER::TestPinToPin()
if( erc != PIN_ERROR::OK && m_settings.IsTestEnabled( ERCE_PIN_TO_PIN_WARNING ) ) if( erc != PIN_ERROR::OK && m_settings.IsTestEnabled( ERCE_PIN_TO_PIN_WARNING ) )
{ {
pin_mismatches.emplace_back(
std::tuple<iterator_t, iterator_t, PIN_ERROR>{ refIt, testIt, erc } );
if( m_settings.GetERCSortingMetric() == ERC_PIN_SORTING_METRIC::SM_HEURISTICS )
{
pin_mismatch_counts[refIt] =
m_settings.GetPinTypeWeight( ( *refIt ).Pin()->GetType() );
pin_mismatch_counts[testIt] =
m_settings.GetPinTypeWeight( ( *testIt ).Pin()->GetType() );
}
else
{
if( !pin_mismatch_counts.contains( testIt ) )
pin_mismatch_counts.emplace( testIt, 1 );
else
pin_mismatch_counts[testIt]++;
if( !pin_mismatch_counts.contains( refIt ) )
pin_mismatch_counts.emplace( refIt, 1 );
else
pin_mismatch_counts[refIt]++;
}
}
}
}
std::multimap<size_t, iterator_t, std::greater<size_t>> pins_dsc;
std::transform( pin_mismatch_counts.begin(), pin_mismatch_counts.end(),
std::inserter( pins_dsc, pins_dsc.begin() ),
[]( const auto& p )
{
return std::pair<size_t, iterator_t>( p.second, p.first );
} );
for( const auto& [amount, pinIt] : pins_dsc )
{
if( pin_mismatches.empty() )
break;
SCH_PIN* pin = ( *pinIt ).Pin();
VECTOR2I position = pin->GetPosition();
iterator_t nearest_pin = pins.end();
double smallest_distance = std::numeric_limits<double>::infinity();
PIN_ERROR erc;
std::erase_if(
pin_mismatches,
[&]( const auto& tuple )
{
iterator_t other;
if( pinIt == std::get<0>( tuple ) )
other = std::get<1>( tuple );
else if( pinIt == std::get<1>( tuple ) )
other = std::get<0>( tuple );
else
return false;
if( ( *pinIt ).Sheet().Cmp( ( *other ).Sheet() ) != 0 )
{
if( std::isinf( smallest_distance ) )
{
nearest_pin = other;
erc = std::get<2>( tuple );
}
}
else
{
double distance = position.Distance( ( *other ).Pin()->GetPosition() );
if( std::isinf( smallest_distance ) || distance < smallest_distance )
{
smallest_distance = distance;
nearest_pin = other;
erc = std::get<2>( tuple );
}
}
return true;
} );
if( nearest_pin != pins.end() )
{
SCH_PIN* other_pin = ( *nearest_pin ).Pin();
std::shared_ptr<ERC_ITEM> ercItem = std::shared_ptr<ERC_ITEM> ercItem =
ERC_ITEM::Create( erc == PIN_ERROR::WARNING ? ERCE_PIN_TO_PIN_WARNING : ERC_ITEM::Create( erc == PIN_ERROR::WARNING ? ERCE_PIN_TO_PIN_WARNING
ERCE_PIN_TO_PIN_ERROR ); : ERCE_PIN_TO_PIN_ERROR );
ercItem->SetItems( refPin.Pin(), testPin.Pin() ); ercItem->SetItems( pin, other_pin );
ercItem->SetSheetSpecificPath( refPin.Sheet() ); ercItem->SetSheetSpecificPath( ( *pinIt ).Sheet() );
ercItem->SetItemsSheetPaths( refPin.Sheet(), testPin.Sheet() ); ercItem->SetItemsSheetPaths( ( *pinIt ).Sheet(), ( *nearest_pin ).Sheet() );
ercItem->SetErrorMessage( ercItem->SetErrorMessage(
wxString::Format( _( "Pins of type %s and %s are connected" ), wxString::Format( _( "Pins of type %s and %s are connected" ),
ElectricalPinTypeGetText( refType ), ElectricalPinTypeGetText( pin->GetType() ),
ElectricalPinTypeGetText( testType ) ) ); ElectricalPinTypeGetText( other_pin->GetType() ) ) );
SCH_MARKER* marker = new SCH_MARKER( ercItem, refPin.Pin()->GetPosition() ); SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetPosition() );
pinToScreenMap[refPin.Pin()]->Append( marker ); pinToScreenMap[pin]->Append( marker );
errors++; errors++;
} }
} }
}
if( needsDriver.Pin() && !hasDriver && !has_noconnect ) if( needsDriver.Pin() && !hasDriver && !has_noconnect )
{ {

View File

@ -232,6 +232,22 @@ ERC_SETTINGS::ERC_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) :
} }
}, },
{} ) ); {} ) );
// Pin weights used for sorting. Take care, sorting is descending!
m_PinTypeWeights.emplace( ELECTRICAL_PINTYPE::PT_NIC, 11 );
m_PinTypeWeights.emplace( ELECTRICAL_PINTYPE::PT_UNSPECIFIED, 10 );
m_PinTypeWeights.emplace( ELECTRICAL_PINTYPE::PT_PASSIVE, 9 );
m_PinTypeWeights.emplace( ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR, 8 );
m_PinTypeWeights.emplace( ELECTRICAL_PINTYPE::PT_OPENEMITTER, 7 );
m_PinTypeWeights.emplace( ELECTRICAL_PINTYPE::PT_INPUT, 6 );
m_PinTypeWeights.emplace( ELECTRICAL_PINTYPE::PT_TRISTATE, 5 );
m_PinTypeWeights.emplace( ELECTRICAL_PINTYPE::PT_BIDI, 4 );
m_PinTypeWeights.emplace( ELECTRICAL_PINTYPE::PT_OUTPUT, 3 );
m_PinTypeWeights.emplace( ELECTRICAL_PINTYPE::PT_POWER_IN, 2 );
m_PinTypeWeights.emplace( ELECTRICAL_PINTYPE::PT_POWER_OUT, 1 );
m_PinTypeWeights.emplace( ELECTRICAL_PINTYPE::PT_NC, 0 );
m_ERCSortingMetric = ERC_PIN_SORTING_METRIC::SM_HEURISTICS;
} }

View File

@ -111,6 +111,13 @@ enum class PIN_ERROR
UNCONNECTED UNCONNECTED
}; };
/// The sorting metric used for erc resolution of multi-pin errors.
enum class ERC_PIN_SORTING_METRIC
{
SM_HEURISTICS,
SM_VIOLATION_COUNT
};
/// Types of drive on a net (used for legacy ERC) /// Types of drive on a net (used for legacy ERC)
#define NPI 4 // Net with Pin isolated, this pin has type Not Connected and must be left N.C. #define NPI 4 // Net with Pin isolated, this pin has type Not Connected and must be left N.C.
#define DRV 3 // Net driven by a signal (a pin output for instance) #define DRV 3 // Net driven by a signal (a pin output for instance)
@ -152,6 +159,24 @@ public:
void ResetPinMap(); void ResetPinMap();
/**
* Get the weight for an electrical pin type.
* Used for sorting of pins in pin-to-pin erc resolution.
* @param aPinType the pin type to check
* @returns the weight for sorting
*/
int GetPinTypeWeight( ELECTRICAL_PINTYPE aPinType ) const
{
wxASSERT( static_cast<int>( aPinType ) < ELECTRICAL_PINTYPES_TOTAL );
return m_PinTypeWeights.at( aPinType );
}
/**
* Get the type of sorting metric the ERC checker should
* use to resolve multi-pin errors.
*/
ERC_PIN_SORTING_METRIC GetERCSortingMetric() const { return m_ERCSortingMetric; }
PIN_ERROR GetPinMapValue( int aFirstType, int aSecondType ) const PIN_ERROR GetPinMapValue( int aFirstType, int aSecondType ) const
{ {
wxASSERT( aFirstType < ELECTRICAL_PINTYPES_TOTAL wxASSERT( aFirstType < ELECTRICAL_PINTYPES_TOTAL
@ -195,6 +220,19 @@ public:
private: private:
static PIN_ERROR m_defaultPinMap[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL]; static PIN_ERROR m_defaultPinMap[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL];
/**
* Weights for electrical pins used in ERC
* to decide which pin gets the marker
* in case of a multi-pin erc pin-to-pin error.
*/
std::map<ELECTRICAL_PINTYPE, int> m_PinTypeWeights;
/**
* The type of sorting used by the ERC checker
* to resolve multi-pin errors.
*/
ERC_PIN_SORTING_METRIC m_ERCSortingMetric;
}; };

View File

@ -0,0 +1,384 @@
{
"board": {
"3dviewports": [],
"ipc2581": {
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": ""
},
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
2,
2,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
2,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
2,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"conflicting_netclasses": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"endpoint_off_grid": "warning",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"missing_bidi_pin": "warning",
"missing_input_pin": "warning",
"missing_power_pin": "error",
"missing_unit": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "error",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"simulation_model_issue": "ignore",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "erc_multiple_pin_to_pin.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2,
"via_diameter": 0.6,
"via_drill": 0.3,
"wire_width": 6
}
],
"meta": {
"version": 3
},
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"plot": "",
"pos_files": "",
"specctra_dsn": "",
"step": "",
"svg": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"bom_export_filename": "",
"bom_fmt_presets": [],
"bom_fmt_settings": {
"field_delimiter": ",",
"keep_line_breaks": false,
"keep_tabs": false,
"name": "CSV",
"ref_delimiter": ",",
"ref_range_delimiter": "",
"string_delimiter": "\""
},
"bom_presets": [],
"bom_settings": {
"exclude_dnp": false,
"fields_ordered": [
{
"group_by": false,
"label": "Reference",
"name": "Reference",
"show": true
},
{
"group_by": true,
"label": "Value",
"name": "Value",
"show": true
},
{
"group_by": false,
"label": "Datasheet",
"name": "Datasheet",
"show": true
},
{
"group_by": false,
"label": "Footprint",
"name": "Footprint",
"show": true
},
{
"group_by": false,
"label": "Qty",
"name": "${QUANTITY}",
"show": true
},
{
"group_by": true,
"label": "DNP",
"name": "${DNP}",
"show": true
}
],
"filter_string": "",
"group_symbols": true,
"name": "Grouped By Value",
"sort_asc": true,
"sort_field": "Reference"
},
"connection_grid_size": 50.0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"operating_point_overlay_i_precision": 3,
"operating_point_overlay_i_range": "~A",
"operating_point_overlay_v_precision": 3,
"operating_point_overlay_v_range": "~V",
"overbar_offset_ratio": 1.23,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"page_layout_descr_file": "",
"plot_directory": "",
"spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"",
"spice_model_current_sheet_as_root": true,
"spice_save_all_currents": false,
"spice_save_all_dissipations": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"c9b0dfd9-0180-4a78-8afb-2260035ff793",
""
]
],
"text_variables": {}
}

File diff suppressed because it is too large Load Diff

View File

@ -53,6 +53,7 @@ set( QA_EESCHEMA_SRCS
erc/test_erc_four_way.cpp erc/test_erc_four_way.cpp
erc/test_erc_label_not_connected.cpp erc/test_erc_label_not_connected.cpp
erc/test_erc_multiple_pin_to_pin.cpp
erc/test_erc_stacking_pins.cpp erc/test_erc_stacking_pins.cpp
erc/test_erc_label_names.cpp erc/test_erc_label_names.cpp
erc/test_erc_global_labels.cpp erc/test_erc_global_labels.cpp

View File

@ -0,0 +1,78 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 KiCad Developers, see AUTHORS.TXT for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one at
* http://www.gnu.org/licenses/
*/
#include <qa_utils/wx_utils/unit_test_utils.h>
#include <schematic_utils/schematic_file_util.h>
#include <connection_graph.h>
#include <schematic.h>
#include <erc/erc_settings.h>
#include <erc/erc.h>
#include <erc/erc_report.h>
#include <settings/settings_manager.h>
#include <locale_io.h>
struct ERC_REGRESSION_TEST_FIXTURE
{
ERC_REGRESSION_TEST_FIXTURE() : m_settingsManager( true /* headless */ ) {}
SETTINGS_MANAGER m_settingsManager;
std::unique_ptr<SCHEMATIC> m_schematic;
};
BOOST_FIXTURE_TEST_CASE( ERCMultiplePinToPin, ERC_REGRESSION_TEST_FIXTURE )
{
LOCALE_IO dummy;
std::vector<std::pair<wxString, int>> tests = { { "erc_multiple_pin_to_pin", 2 } };
for( const std::pair<wxString, int>& test : tests )
{
KI_TEST::LoadSchematic( m_settingsManager, test.first, m_schematic );
ERC_SETTINGS& settings = m_schematic->ErcSettings();
SHEETLIST_ERC_ITEMS_PROVIDER errors( m_schematic.get() );
// Skip the "Modified symbol" warning
settings.m_ERCSeverities[ERCE_LIB_SYMBOL_ISSUES] = RPT_SEVERITY_IGNORE;
settings.m_ERCSeverities[ERCE_LIB_SYMBOL_MISMATCH] = RPT_SEVERITY_IGNORE;
m_schematic->ConnectionGraph()->RunERC();
ERC_TESTER tester( m_schematic.get() );
tester.TestConflictingBusAliases();
tester.TestMultUnitPinConflicts();
tester.TestMultiunitFootprints();
tester.TestNoConnectPins();
tester.TestPinToPin();
tester.TestSimilarLabels();
errors.SetSeverities( RPT_SEVERITY_ERROR | RPT_SEVERITY_WARNING );
ERC_REPORT reportWriter( m_schematic.get(), EDA_UNITS::MILLIMETRES );
BOOST_CHECK_MESSAGE( errors.GetCount() == test.second,
"Expected " << test.second << " errors in " << test.first.ToStdString()
<< " but got " << errors.GetCount() << "\n"
<< reportWriter.GetTextReport() );
}
}

View File

@ -47,10 +47,7 @@ BOOST_FIXTURE_TEST_CASE( ERCStackingPins, ERC_REGRESSION_TEST_FIXTURE )
// Check for Errors when stacking pins // Check for Errors when stacking pins
std::vector<std::pair<wxString, int>> tests = std::vector<std::pair<wxString, int>> tests = { { "issue6588", 3 } };
{
{ "issue6588", 5 }
};
for( const std::pair<wxString, int>& test : tests ) for( const std::pair<wxString, int>& test : tests )
{ {