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 <drc/drc_engine.h>
26 #include <drc/drc_item.h>
27 #include <drc/drc_rule.h>
28 #include <drc/drc_test_provider.h>
29 
30 #include <kiway.h>
32 
33 /*
34  Layout-versus-schematic (LVS) test.
35 
36  Errors generated:
37  - DRCE_MISSING_FOOTPRINT
38  - DRCE_DUPLICATE_FOOTPRINT
39  - DRCE_EXTRA_FOOTPRINT
40 
41  TODO:
42  - cross-check PCB netlist against SCH netlist
43  - cross-check PCB fields against SCH fields
44 */
45 
47 {
48 public:
50  {
51  m_isRuleDriven = false;
52  }
53 
55  {
56  }
57 
58  virtual bool Run() override;
59 
60  virtual const wxString GetName() const override
61  {
62  return "LVS";
63  };
64 
65  virtual const wxString GetDescription() const override
66  {
67  return "Performs layout-vs-schematics integity check";
68  }
69 
70  virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
71 
72  int GetNumPhases() const override;
73 
74 private:
75  void testFootprints( NETLIST& aNetlist );
76 };
77 
78 
80 {
81  BOARD* board = m_drcEngine->GetBoard();
82 
83  auto compare = []( const FOOTPRINT* x, const FOOTPRINT* y )
84  {
85  return x->GetReference().CmpNoCase( y->GetReference() ) < 0;
86  };
87 
88  auto footprints = std::set<FOOTPRINT*, decltype( compare )>( compare );
89 
90  // Search for duplicate footprints on the board
91  for( FOOTPRINT* footprint : board->Footprints() )
92  {
94  break;
95 
96  auto ins = footprints.insert( footprint );
97 
98  if( !ins.second )
99  {
100  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_DUPLICATE_FOOTPRINT );
101  drcItem->SetItems( footprint, *ins.first );
102 
103  reportViolation( drcItem, footprint->GetPosition() );
104  }
105  }
106 
107  // Search for component footprints in the netlist but not on the board.
108  for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ )
109  {
110  COMPONENT* component = aNetlist.GetComponent( ii );
111  FOOTPRINT* footprint = board->FindFootprintByReference( component->GetReference() );
112 
113  if( footprint == nullptr )
114  {
116  break;
117 
118  m_msg.Printf( _( "Missing footprint %s (%s)" ),
119  component->GetReference(),
120  component->GetValue() );
121 
122  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT );
123 
124  drcItem->SetErrorMessage( m_msg );
125  reportViolation( drcItem, wxPoint() );
126  }
127  else
128  {
129  for( PAD* pad : footprint->Pads() )
130  {
132  break;
133 
134  const COMPONENT_NET& sch_net = component->GetNet( pad->GetName() );
135  const wxString& pcb_netname = pad->GetNetname();
136 
137  if( !pcb_netname.IsEmpty() && sch_net.GetPinName().IsEmpty() )
138  {
139  m_msg.Printf( _( "No corresponding pin found in schematic." ) );
140 
141  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
142  drcItem->SetErrorMessage( m_msg );
143  drcItem->SetItems( pad );
144  reportViolation( drcItem, footprint->GetPosition() );
145  }
146  else if( pcb_netname.IsEmpty() && !sch_net.GetNetName().IsEmpty() )
147  {
148  m_msg.Printf( _( "Pad missing net given by schematic (%s)." ),
149  sch_net.GetNetName() );
150 
151  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
152  drcItem->SetErrorMessage( m_msg );
153  drcItem->SetItems( pad );
154  reportViolation( drcItem, footprint->GetPosition() );
155  }
156  else if( pcb_netname != sch_net.GetNetName() )
157  {
158  m_msg.Printf( _( "Pad net (%s) doesn't match net given by schematic (%s)." ),
159  pcb_netname,
160  sch_net.GetNetName() );
161 
162  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
163  drcItem->SetErrorMessage( m_msg );
164  drcItem->SetItems( pad );
165  reportViolation( drcItem, footprint->GetPosition() );
166  }
167  }
168 
169  for( unsigned jj = 0; jj < component->GetNetCount(); ++jj )
170  {
172  break;
173 
174  const COMPONENT_NET& sch_net = component->GetNet( jj );
175 
176  if( !footprint->FindPadByName( sch_net.GetPinName() ) )
177  {
178  m_msg.Printf( _( "No pad found for pin %s in schematic." ),
179  sch_net.GetPinName() );
180 
181  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_NET_CONFLICT );
182  drcItem->SetErrorMessage( m_msg );
183  drcItem->SetItems( footprint );
184  reportViolation( drcItem, footprint->GetPosition() );
185  }
186  }
187  }
188  }
189 
190  // Search for component footprints found on board but not in netlist.
191  for( FOOTPRINT* footprint : board->Footprints() )
192  {
194  break;
195 
196  if( footprint->GetAttributes() & FP_BOARD_ONLY )
197  continue;
198 
199  if( !aNetlist.GetComponentByReference( footprint->GetReference() ) )
200  {
201  std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_EXTRA_FOOTPRINT );
202 
203  drcItem->SetItems( footprint );
204  reportViolation( drcItem, footprint->GetPosition() );
205  }
206  }
207 }
208 
209 
211 {
213  {
214  if( !reportPhase( _( "Checking PCB to schematic parity..." ) ) )
215  return false;
216 
217  auto netlist = m_drcEngine->GetSchematicNetlist();
218 
219  if( !netlist )
220  {
221  reportAux( _("No netlist provided, skipping LVS.") );
222  return true;
223  }
224 
225  testFootprints( *netlist );
226 
228  }
229 
230  return true;
231 }
232 
233 
235 {
236  return m_drcEngine->GetTestFootprints() ? 1 : 0;
237 }
238 
239 
240 std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_LVS::GetConstraintTypes() const
241 {
242  return {};
243 }
244 
245 
246 namespace detail
247 {
249 }
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:245
virtual bool Run() override
Runs this provider against the given PCB with configured options (if any).
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULUS > dummy
bool IsErrorLimitExceeded(int error_code)
virtual const wxString GetName() const override
unsigned GetCount() const
Function GetCount.
Definition: pcb_netlist.h:237
virtual void reportRuleStatistics()
PADS & Pads()
Definition: footprint.h:164
COMPONENT_NET is used to store the component pin name to net name (and pin function) associations sto...
Definition: pcb_netlist.h:44
const wxString & GetNetName() const
Definition: pcb_netlist.h:64
bool GetTestFootprints() const
Definition: drc_engine.h:153
NETLIST stores all of information read from a netlist along with the flags used to update the NETLIST...
Definition: pcb_netlist.h:207
BOARD * GetBoard() const
Definition: drc_engine.h:87
virtual bool reportPhase(const wxString &aStageName)
unsigned GetNetCount() const
Definition: pcb_netlist.h:144
FOOTPRINTS & Footprints()
Definition: board.h:296
const wxString & GetReference() const
Definition: pcb_netlist.h:158
virtual std::set< DRC_CONSTRAINT_T > GetConstraintTypes() const override
const wxString & GetReference() const
Definition: footprint.h:423
PAD * FindPadByName(const wxString &aPadName) const
Return a PAD with a matching name.
Definition: footprint.cpp:956
const COMPONENT_NET & GetNet(unsigned aIndex) const
Definition: pcb_netlist.h:146
virtual const wxString GetDescription() const override
COMPONENT is used to store components and all of their related information found in a netlist.
Definition: pcb_netlist.h:85
COMPONENT * GetComponent(unsigned aIndex)
Function GetComponent returns the COMPONENT at aIndex.
Definition: pcb_netlist.h:246
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, wxPoint aMarkerPos)
DRC_TEST_PROVIDER is a base class that represents a DRC "provider" which runs some DRC functions over...
NETLIST * GetSchematicNetlist() const
Definition: drc_engine.h:93
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:189
#define _(s)
Definition: 3d_actions.cpp:33
DRC_ENGINE * m_drcEngine
wxPoint GetPosition() const override
Definition: footprint.h:182
const wxString & GetPinName() const
Definition: pcb_netlist.h:63
void testFootprints(NETLIST &aNetlist)
const wxString & GetValue() const
Definition: pcb_netlist.h:159
COMPONENT * GetComponentByReference(const wxString &aReference)
Function GetComponentByReference returns a COMPONENT by aReference.
Definition: pad.h:60
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:1289
int GetNumPhases() const override