Xorn
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
netlist.py
Go to the documentation of this file.
1 # xorn.geda.netlist - gEDA Netlist Extraction and Generation
2 # Copyright (C) 1998-2010 Ales Hvezda
3 # Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
4 # Copyright (C) 2013-2016 Roland Lutz
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (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, write to the Free Software Foundation,
18 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ## \namespace xorn.geda.netlist.netlist
21 ## Main entry point for netlist generation.
22 #
23 # See the class Netlist for details.
24 
25 import os, sys
26 from gettext import gettext as _
27 import xorn.geda.attrib
28 import xorn.geda.read
38 
39 ## Global netlist object representing the result of a netlister run.
40 
41 class Netlist:
42  ## Create a netlist.
43  #
44  # This is the main function which creates a netlist. The most
45  # important argument is \a toplevel_filenames; it contains the
46  # filenames of the schematic pages which should be traversed.
47  # Other schematic pages are loaded as necessary if the \a
48  # traverse_hierarchy argument is set.
49  #
50  # \param [in] toplevel_filenames
51  # list of filenames for the toplevel schematics, as given on
52  # the command line
53  #
54  # \param [in] traverse_hierarchy
55  # whether to descend into sub-schematics
56  #
57  # \param [in] verbose_mode
58  # whether to print "Loading schematic" and "Going to traverse
59  # source" messages
60  #
61  # \param [in] prefer_netname_attribute
62  # whether to prefer net names set via a net segment's \c
63  # netname= attribute over net names set via a pin's \c net=
64  # attribute
65  #
66  # \param [in] flat_package_namespace
67  # whether to use a common package namespace for all subsheets
68  #
69  # \param [in] flat_netname_namespace
70  # whether to use a common \c netname= namespace for all subsheets
71  #
72  # \param [in] flat_netattrib_namespace
73  # whether to use a common \c net= namespace for all subsheets
74  #
75  # \param [in] refdes_mangle_func
76  # function for mangling package/component refdes's
77  #
78  # \param [in] netname_mangle_func
79  # function for mangling net names
80  #
81  # \param [in] default_net_name
82  # naming template for unnamed nets
83  #
84  # \param [in] default_bus_name
85  # naming template for unnamed buses
86 
87  def __init__(self, toplevel_filenames,
88  traverse_hierarchy,
89  verbose_mode = False,
90  prefer_netname_attribute = False,
91  flat_package_namespace = False,
92  flat_netname_namespace = False,
93  flat_netattrib_namespace = False,
94  refdes_mangle_func = NotImplemented,
95  netname_mangle_func = NotImplemented,
96  default_net_name = 'unnamed_net',
97  default_bus_name = 'unnamed_bus'):
98  ## Aggregated list of all components in the netlist.
99  self.components = []
100  ## List of sheets for the schematics named on the command line.
101  self.toplevel_sheets = []
102  ## List of sheets.
103  self.sheets = []
104 
105  ## Whether an error has occurred.
106  self.failed = False
107 
108  ## List of nets.
109  #
110  # Populated by xorn.geda.netlist.net.
111  self.nets = None
112 
113  ## List of packages.
114  #
115  # Populated by xorn.geda.netlist.package.
116  self.packages = None
117 
118  ## Convenience dictionary for looking up packages by their refdes.
119  self.packages_by_refdes = None
120 
121  ## Convenience dictionary for looking up nets by their name.
122  self.nets_by_name = None
123 
124  ## List of schematic blueprints.
125  self.schematics = []
126  ## Dictionary mapping filenames to schematic blueprints.
128 
129 
130  def load_schematic(filename):
131  if filename in self.schematics_by_filename:
132  return
133 
134  self.schematics_by_filename[filename] = None
135 
136  if verbose_mode:
137  sys.stderr.write(_("Loading schematic [%s]\n") % filename)
138 
139  try:
140  rev = xorn.geda.read.read(filename, load_symbols = True)
141  except Exception as e:
142  sys.stderr.write(_("ERROR: Failed to load '%s': %s\n")
143  % (filename, e))
144  sys.exit(2)
145 
146  rev.finalize()
148  rev, filename, self)
149  self.schematics.append(schematic)
150  self.schematics_by_filename[filename] = schematic
151 
152  # Check if the component object represents a subsheet (i.e.,
153  # has a "source=" attribute), and if so, get the filenames.
154 
155  for component in schematic.components:
156  component.composite_sources = []
157 
158  for value in component.get_attributes('source'):
159  for filename in value.split(','):
160  if filename.startswith(' '):
161  warn(_("leading spaces in source names "
162  "are deprecated"))
163  filename = filename.lstrip(' ')
164 
165  full_filename = \
167  filename)
168  if full_filename is None:
169  component.error(
170  _("failed to load subcircuit '%s': "
171  "schematic not found in source library")
172  % filename)
173  continue
174 
175  if verbose_mode:
176  sys.stderr.write(
177  _("Going to traverse source [%s]\n")
178  % full_filename)
179  load_schematic(full_filename)
180  component.composite_sources.append(
181  self.schematics_by_filename[full_filename])
182 
183  for filename in toplevel_filenames:
184  load_schematic(filename)
185 
190 
191  # Traverse the schematic files and create the component objects
192  # accordingly.
193 
194  def s_traverse_sheet1(sheet):
195  for component in sheet.components:
196  # now you need to traverse any underlying schematics
197 
198  # Check if the component object represents a subsheet (i.e.,
199  # has a "source=" attribute), and if so, traverse that sheet.
200 
201  for subschematic in component.blueprint.composite_sources:
202  # can't do the following, don't know why... HACK TODO
203  #component.hierarchy_tag = u_basic_strdup(refdes)
205  component.sheet.netlist, subschematic, component)
206  s_traverse_sheet1(subsheet)
207 
208  for filename in toplevel_filenames:
210  self, self.schematics_by_filename[filename], None)
211  self.toplevel_sheets.append(sheet)
212  if traverse_hierarchy:
213  s_traverse_sheet1(sheet)
214 
215  # now that all the sheets have been read, go through and do the
216  # post processing work
217 
218  # List the components in the same order as gnetlist.
219 
220  def collect_components(sheet):
221  for component in sheet.components:
222  sheet.netlist.components.append(component)
223  for subsheet in component.subsheets:
224  collect_components(subsheet)
225 
226  for sheet in self.toplevel_sheets:
227  collect_components(sheet)
228 
229  # create net objects
231  self, { False: flat_netname_namespace,
232  True: flat_netattrib_namespace },
233  prefer_netname_attribute,
234  default_net_name, default_bus_name)
235 
236  # assign net names
237  for net in self.nets:
238  net.name = netname_mangle_func(
239  net.unmangled_name, net.namespace)
240 
241  # assign component pins
242  for component in self.components:
243  for cpin in component.cpins:
244  if (component.sheet, cpin.blueprint.net) \
245  not in cpin.local_net.net.sheets_and_net_blueprints:
246  cpin.local_net.net.sheets_and_net_blueprints.append(
247  (component.sheet, cpin.blueprint.net))
248 
249  for net in self.nets:
250  for sheet, net_blueprint in net.sheets_and_net_blueprints:
251  for cpin_blueprint in net_blueprint.pins:
252  if cpin_blueprint.ob is not None:
253  assert cpin_blueprint.ob.data().is_pin
254 
255  cpin = sheet \
256  .components_by_blueprint[cpin_blueprint.component] \
257  .cpins_by_blueprint[cpin_blueprint]
258 
259  assert cpin not in net.component_pins
260  net.component_pins.append(cpin)
261 
262  # Resolve hierarchy
264 
266 
267  # group components into packages
269  self, flat_package_namespace)
270 
271  # remove nets for unconnected pins
272  self.nets = [net for net in self.nets if not net.is_unconnected_pin]
273 
274 
275  # assign component refdes
276  for component in self.components:
277  if component.blueprint.refdes is not None:
278  if component.sheet.instantiating_component is not None:
279  namespace = component.sheet
280  else:
281  namespace = None
282  component.refdes = refdes_mangle_func(
283  component.blueprint.refdes, namespace)
284 
285  # assign package refdes
286  for package in self.packages:
287  if package.namespace is not None:
288  package.refdes = refdes_mangle_func(
289  package.unmangled_refdes, package.namespace)
290  else:
291  # If refdes mangling is disabled, packages don't have
292  # a sheet attribute, so just use the unmangled refdes.
293  package.refdes = package.unmangled_refdes
294 
295  # compile convenience hashes, checking for cross-page name clashes
296  self.packages_by_refdes = {}
297  for package in self.packages:
298  if package.refdes in self.packages_by_refdes:
299  other_package = self.packages_by_refdes[package.refdes]
300  self.error(_("refdes conflict across hierarchy: "
301  "refdes `%s' is used by package `%s' on page "
302  "`%s' and by package `%s' on page `%s'") % (
303  package.refdes,
304  other_package.unmangled_refdes,
305  refdes_mangle_func('', other_package.namespace),
306  package.unmangled_refdes,
307  refdes_mangle_func('', package.namespace)))
308  self.packages_by_refdes[package.refdes] = package
309 
310  self.nets_by_name = {}
311  for net in self.nets:
312  if net.name in self.nets_by_name:
313  other_net = self.nets_by_name[net.name]
314  self.error(_("net name conflict across hierarchy: "
315  "net name `%s' is used by net `%s' on page "
316  "`%s' and by net `%s' on page `%s'") % (
317  net.name,
318  other_net.unmangled_name,
319  netname_mangle_func('', other_net.namespace),
320  net.unmangled_name,
321  netname_mangle_func('', net.namespace)))
322  self.nets_by_name[net.name] = net
323 
324  ## Return the value of a toplevel attribute.
325  #
326  # Searches for an floating attribute with the name \a name in the
327  # schematic files listed on the command line. Calls \ref error if
328  # multiple attributes with different values are found.
329  #
330  # Traditionally, this function returned <tt>'not found'</tt> when
331  # no such attribute existed in the toplevel schematic.
332  #
333  # \throws ValueError if no matching attribute was found and no \a
334  # default was given
335 
336  def get_toplevel_attribute(self, name, default = KeyError):
337  if not isinstance(name, basestring):
338  raise ValueError
339 
340  values = []
341  for sheet in self.toplevel_sheets:
343  sheet.blueprint.rev, name)
344 
345  if values:
346  for value in values[1:]:
347  if value != values[0]:
348  self.error(
349  _("inconsistent values for toplevel attribute "
350  "\"%s\": %s") % (
351  name, _(" vs. ").join(_("\"%s\"") % value
352  for value in values)))
353  return values[0]
354  return values[0]
355 
356  if default is not KeyError:
357  return default
358  raise KeyError
359 
360  ## Print an error message and mark the netlist as failed.
361 
362  def error(self, msg):
363  sys.stderr.write(_("error: %s\n" % msg))
364  self.failed = True
365 
366  ## Print a warning message.
367 
368  def warn(self, msg):
369  sys.stderr.write(_("warning: %s\n" % msg))
components
Aggregated list of all components in the netlist.
Definition: netlist.py:99
Post-processing: Slotting mechanism.
Definition: pp_slotting.py:1
Attribute parsing and lookup.
Definition: attrib.py:1
toplevel_sheets
List of sheets for the schematics named on the command line.
Definition: netlist.py:101
Reading schematic/symbol files.
Definition: read.py:1
Post-processing: Artificial pins.
Definition: pp_netattrib.py:1
def search_floating
Search the floating attributes in a revision for an attribute name and return matching values...
Definition: attrib.py:152
Grouping local nets with the same name into a net.
Definition: net.py:1
def get_toplevel_attribute
Return the value of a toplevel attribute.
Definition: netlist.py:336
def __init__
Create a netlist.
Definition: netlist.py:97
def postproc_instances
Definition: net.py:101
Netlists for individual schematic files.
Definition: blueprint.py:1
Building one hierarchical netlist from instantiated sheet blueprints.
Definition: instance.py:1
packages
List of packages.
Definition: netlist.py:116
def error
Print an error message and mark the netlist as failed.
Definition: netlist.py:362
Post-processing: Graphical components.
Definition: pp_graphical.py:1
def read
Read a symbol or schematic file.
Definition: read.py:71
failed
Whether an error has occurred.
Definition: netlist.py:106
schematics_by_filename
Dictionary mapping filenames to schematic blueprints.
Definition: netlist.py:127
Instantiation of a schematic page.
Definition: instance.py:32
Source library.
Definition: slib.py:1
Global netlist object representing the result of a netlister run.
Definition: netlist.py:41
A netlist for a single schematic.
Definition: blueprint.py:45
Post-processing: Hierarchy traversal.
Definition: pp_hierarchy.py:1
Grouping components with the same refdes into a package.
Definition: package.py:1
nets_by_name
Convenience dictionary for looking up nets by their name.
Definition: netlist.py:122
def postproc_instances
Connect subsheet I/O ports to the instantiating component's pins.
Definition: pp_hierarchy.py:32
def warn
Print a warning message.
Definition: netlist.py:368
def s_slib_search_single
Search the source library for a particular file name substring.
Definition: slib.py:44
packages_by_refdes
Convenience dictionary for looking up packages by their refdes.
Definition: netlist.py:119
schematics
List of schematic blueprints.
Definition: netlist.py:125