KiCad PCB EDA Suite
drc_test_provider_lvs.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2004-2020 KiCad Developers.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 #include <board.h>
25 #include <pad.h>
26 #include <drc/drc_engine.h>
27 #include <drc/drc_item.h>
28 #include <drc/drc_rule.h>
29 #include <drc/drc_test_provider.h>
30 
31 #include <kiway.h>
33 
34 /*
35  Layout-versus-schematic (LVS) test.
36 
37  Errors generated:
38  - DRCE_MISSING_FOOTPRINT
39  - DRCE_DUPLICATE_FOOTPRINT
40  - DRCE_EXTRA_FOOTPRINT
41 
42  TODO:
43  - cross-check PCB netlist against SCH netlist
44  - cross-check PCB fields against SCH fields
45 */
46 
48 {
49 public:
51  {
52  m_isRuleDriven = false;
53  }
54 
56  {
57  }
58 
59  virtual bool Run() override;
60 
61  virtual const wxString GetName() const override
62  {
63  return "LVS";
64  };
65 
66  virtual const wxString GetDescription() const override
67  {
68  return "Performs layout-vs-schematics integity check";
69  }
70 
71  virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
72 
73  int GetNumPhases() const override;
74 
75 private:
76  void testFootprints( NETLIST& aNetlist );
77 };
78 
79 
81 {
82  BOARD* board = m_drcEngine->GetBoard();
83 
84  auto compare = []( const FOOTPRINT* x, const FOOTPRINT* y )
85  {
86  return x->GetReference().CmpNoCase( y->GetReference() ) < 0;
87  };
88 
89  auto footprints = std::set<FOOTPRINT*, decltype( compare )>( compare );
90 
91  // Search for duplicate footprints on the board
92  for( FOOTPRINT* footprint : board->Footprints() )
93  {
95  break;
96 
97  auto ins = footprints.insert( footprint );
98 
99  if( !ins.second && !( footprint->GetAttributes() & FP_BOARD_ONLY ) )
100  {
101  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_DUPLICATE_FOOTPRINT );
102  drcItem->SetItems( footprint, *ins.first );
103 
104  reportViolation( drcItem, footprint->GetPosition() );
105  }
106  }
107 
108  // Search for component footprints in the netlist but not on the board.
109  for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ )
110  {
111  COMPONENT* component = aNetlist.GetComponent( ii );
112  FOOTPRINT* footprint = board->FindFootprintByReference( component->GetReference() );
113 
114  if( footprint == nullptr )
115  {
117  break;
118 
119  m_msg.Printf( _( "Missing footprint %s (%s)" ),
120  component->GetReference(),
121  component->GetValue() );
122 
123  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT );
124 
125  drcItem->SetErrorMessage( m_msg );
126  reportViolation( drcItem, wxPoint() );
127  }
128  else
129  {
130  for( PAD* pad : footprint->Pads() )
131  {
133  break;
134 
135  if( !pad->CanHaveNumber() )
136  continue;
137 
138  const COMPONENT_NET& sch_net = component->GetNet( pad->GetNumber() );
139  const wxString& pcb_netname = pad->GetNetname();
140 
141  if( !pcb_netname.IsEmpty() && sch_net.GetPinName().IsEmpty() )
142  {
143  m_msg.Printf( _( "No corresponding pin found in schematic." ) );
144 
145  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
146  drcItem->SetErrorMessage( m_msg );
147  drcItem->SetItems( pad );
148  reportViolation( drcItem, footprint->GetPosition() );
149  }
150  else if( pcb_netname.IsEmpty() && !sch_net.GetNetName().IsEmpty() )
151  {
152  m_msg.Printf( _( "Pad missing net given by schematic (%s)." ),
153  sch_net.GetNetName() );
154 
155  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
156  drcItem->SetErrorMessage( m_msg );
157  drcItem->SetItems( pad );
158  reportViolation( drcItem, footprint->GetPosition() );
159  }
160  else if( pcb_netname != sch_net.GetNetName() )
161  {
162  m_msg.Printf( _( "Pad net (%s) doesn't match net given by schematic (%s)." ),
163  pcb_netname,
164  sch_net.GetNetName() );
165 
166  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
167  drcItem->SetErrorMessage( m_msg );
168  drcItem->SetItems( pad );
169  reportViolation( drcItem, footprint->GetPosition() );
170  }
171  }
172 
173  for( unsigned jj = 0; jj < component->GetNetCount(); ++jj )
174  {
176  break;
177 
178  const COMPONENT_NET& sch_net = component->GetNet( jj );
179 
180  if( !footprint->FindPadByNumber( sch_net.GetPinName() ) )
181  {
182  m_msg.Printf( _( "No pad found for pin %s in schematic." ),
183  sch_net.GetPinName() );
184 
185  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
186  drcItem->SetErrorMessage( m_msg );
187  drcItem->SetItems( footprint );
188  reportViolation( drcItem, footprint->GetPosition() );
189  }
190  }
191  }
192  }
193 
194  // Search for component footprints found on board but not in netlist.
195  for( FOOTPRINT* footprint : board->Footprints() )
196  {
198  break;
199 
200  if( footprint->GetAttributes() & FP_BOARD_ONLY )
201  continue;
202 
203  if( !aNetlist.GetComponentByReference( footprint->GetReference() ) )
204  {
205  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_EXTRA_FOOTPRINT );
206 
207  drcItem->SetItems( footprint );
208  reportViolation( drcItem, footprint->GetPosition() );
209  }
210  }
211 }
212 
213 
215 {
217  {
218  if( !reportPhase( _( "Checking PCB to schematic parity..." ) ) )
219  return false;
220 
222 
223  if( !netlist )
224  {
225  reportAux( _("No netlist provided, skipping LVS.") );
226  return true;
227  }
228 
230 
232  }
233 
234  return true;
235 }
236 
237 
239 {
240  return m_drcEngine->GetTestFootprints() ? 1 : 0;
241 }
242 
243 
244 std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_LVS::GetConstraintTypes() const
245 {
246  return {};
247 }
248 
249 
250 namespace detail
251 {
253 }
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:266
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const wxPoint &aMarkerPos)
bool IsErrorLimitExceeded(int error_code)
virtual const wxString GetName() const override
unsigned GetCount() const
Definition: pcb_netlist.h:228
virtual void reportRuleStatistics()
PADS & Pads()
Definition: footprint.h:168
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
Used to store the component pin name to net name (and pin function) associations stored in a netlist.
Definition: pcb_netlist.h:43
const wxString & GetNetName() const
Definition: pcb_netlist.h:58
bool GetTestFootprints() const
Definition: drc_engine.h:157
Store information read from a netlist along with the flags used to update the NETLIST in the BOARD.
Definition: pcb_netlist.h:206
BOARD * GetBoard() const
Definition: drc_engine.h:88
virtual bool reportPhase(const wxString &aStageName)
unsigned GetNetCount() const
Definition: pcb_netlist.h:109
FOOTPRINTS & Footprints()
Definition: board.h:234
const wxString & GetReference() const
Definition: pcb_netlist.h:123
virtual std::set< DRC_CONSTRAINT_T > GetConstraintTypes() const override
PAD * FindPadByNumber(const wxString &aPadNumber, PAD *aSearchAfterMe=nullptr) const
Return a PAD with a matching number.
Definition: footprint.cpp:1074
const wxString & GetReference() const
Definition: footprint.h:463
#define _(s)
const COMPONENT_NET & GetNet(unsigned aIndex) const
Definition: pcb_netlist.h:111
virtual const wxString GetDescription() const override
Store all of the related footprint information found in a netlist.
Definition: pcb_netlist.h:84
COMPONENT * GetComponent(unsigned aIndex)
Return the COMPONENT at aIndex.
Definition: pcb_netlist.h:236
Represent a DRC "provider" which runs some DRC functions over a BOARD and spits out #DRC_ITEMs and po...
NETLIST * GetSchematicNetlist() const
Definition: drc_engine.h:94
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:191
DRC_ENGINE * m_drcEngine
wxPoint GetPosition() const override
Definition: footprint.h:186
const wxString & GetPinName() const
Definition: pcb_netlist.h:57
void testFootprints(NETLIST &aNetlist)
const wxString & GetValue() const
Definition: pcb_netlist.h:124
COMPONENT * GetComponentByReference(const wxString &aReference)
Return a COMPONENT by aReference.
Definition: pad.h:57
virtual void reportAux(wxString fmt,...)
FOOTPRINT * FindFootprintByReference(const wxString &aReference) const
Search for a FOOTPRINT within this board with the given reference designator.
Definition: board.cpp:1346
int GetNumPhases() const override