Xorn
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
package.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.package
21 ## Grouping components with the same refdes into a package.
22 
23 import sys
24 from gettext import gettext as _
25 
26 class Package:
27  def __init__(self, netlist, namespace, unmangled_refdes):
28  self.netlist = netlist
29  self.namespace = namespace
30  self.unmangled_refdes = unmangled_refdes
31  self.refdes = None # set by netlist ctor
32  self.components = []
33  self.pins = []
34  self.pins_by_number = {}
35 
36  ## Get attribute value(s) from a package with given refdes.
37  #
38  # This function returns the values of a specific attribute type
39  # attached to the symbol instances with this package's refdes.
40  #
41  # For each symbol instance, the found attribute value is added to
42  # the return list. \c None is added if the instance has no such
43  # attribute.
44  #
45  # \note The order of the values in the return list is the order of
46  # symbol instances within the netlist (the first element is
47  # the value associated with the first symbol instance).
48  #
49  # \returns a list of attribute values as strings and \c None
50 
51  def get_all_attributes(self, name):
52  if not isinstance(name, basestring):
53  raise ValueError
54 
55  # search for refdes instances and through the entire list
56  l = []
57  for component in self.components:
58  try:
59  value = component.blueprint.get_attribute(name)
60  except KeyError:
61  l.append(None)
62  else:
63  l.append(value)
64  return l
65 
66  ## Return the value associated with attribute \a name on the package.
67  #
68  # It actually computes a single value from the full list of values
69  # produced by \ref get_all_attributes.
70  #
71  # Returns the value associated with the first symbol instance for
72  # \a refdes which has a matching attribute. If all instances of
73  # \a refdes do not have the same value for \a name and \a name is
74  # not \c "slot", raises an error.
75 
76  def get_attribute(self, name, default = KeyError):
77  values = []
78  for value in self.get_all_attributes(name):
79  if value is not None and value not in values:
80  values.append(value)
81 
82  if len(values) > 1:
83  self.error(_("attribute conflict for \"%s\": %s") % (
84  name, _(" vs. ").join(_("\"%s\"") % value
85  for value in values)))
86  values = False
87 
88  if not values:
89  if default is not KeyError:
90  return default
91  raise KeyError
92 
93  assert isinstance(values[0], basestring)
94  return values[0]
95 
96  ## Takes a pinseq string and returns that pinseq pin of this package.
97 
98  def get_pin_by_pinseq(self, pinseq):
99  if not isinstance(pinseq, int):
100  raise ValueError
101 
102  for component in self.components:
103  try:
104  pin_blueprint = component.blueprint.pins_by_pinseq[pinseq]
105  except KeyError:
106  continue
107  return self.pins_by_number[pin_blueprint.number]
108 
109  raise KeyError
110 
111  ## Return a sorted list of slots used by this package.
112  #
113  # It collects the slot attribute values of each symbol instance of
114  # this package. As a result, slots may be repeated in the
115  # returned list.
116 
117  def get_slots(self):
118  l = []
119  for slot in self.get_all_attributes('slot'):
120  if slot is None:
121  # no slot attribute, assume slot number is 1
122  l.append(1)
123  continue
124 
125  # convert string attribute value to number
126  try:
127  l.append(int(slot))
128  except ValueError:
129  # conversion failed, invalid slot, ignore value
130  self.error(_("bad slot number: %s") % slot)
131  l.sort()
132  return l
133 
134  ## Return a sorted list of unique slots used by this package.
135 
136  def get_unique_slots(self):
137  l = list(set(self.get_slots()))
138  l.sort()
139  return l
140 
141  def get_attribute_names(self, search_inherited):
142  # search outside the symbol (attached attributes only)
143  l = []
144  for component in self.components:
145  for name in \
146  component.blueprint.get_attribute_names(search_inherited):
147  if name not in l:
148  l.append(name)
149  return l
150 
151  def error(self, msg):
152  sys.stderr.write(_("package `%s': error: %s\n") % (self.refdes, msg))
153  self.netlist.failed = True
154 
155  def warn(self, msg):
156  sys.stderr.write(_("package `%s': warning: %s\n") % (self.refdes, msg))
157 
158 # ============================================================================
159 
161  def __init__(self, package, number):
162  self.package = package
163  self.number = number
164  self.cpins = []
165 
166  ## Returns the appropriate attribute values on this pin.
167  #
168  # This function returns the values of a specific attribute type
169  # attached to the instances of this pin. For each instance, the
170  # found attribute value is added to the return list. \c None is
171  # added if the instance has no such attribute.
172  #
173  # \note The order of the values in the return list is the order of
174  # pin instances within the netlist (the first element is the
175  # value associated with the first pin instance).
176  #
177  # \returns a list of attribute values as strings and \c None
178 
179  def get_all_attributes(self, name):
180  if not isinstance(name, basestring):
181  raise ValueError
182 
183  l = []
184  for cpin in self.cpins:
185  try:
186  value = cpin.blueprint.get_attribute(name)
187  except KeyError:
188  l.append(None)
189  else:
190  l.append(value)
191  return l
192 
193  ## Return the value associated with attribute \a name on the pin.
194  #
195  # It actually computes a single value from the full list of values
196  # produced by \ref get_all_attributes.
197  #
198  # If all instances do not have the same value for \a name, raises
199  # an error.
200 
201  def get_attribute(self, name, default = KeyError):
202  # Treat "pinnumber" specially: return the value of self.number
203  # which recognizes slotting. For backwards compatibility,
204  # artificial pins do not have a pinnumber.
205 
206  if name == 'pinnumber':
207  has_real_pins = False
208  for cpin in self.cpins:
209  if cpin.blueprint.ob is not None:
210  has_real_pins = True
211 
212  if has_real_pins:
213  return self.number
214  else:
215  if default is not KeyError:
216  return default
217  raise KeyError
218 
219  values = []
220  for value in self.get_all_attributes(name):
221  if value is not None and value not in values:
222  values.append(value)
223 
224  if len(values) > 1:
225  self.error(_("attribute conflict for \"%s\": %s") % (
226  name, _(" vs. ").join(_("\"%s\"") % value
227  for value in values)))
228  values = False
229 
230  if not values:
231  if default is not KeyError:
232  return default
233  raise KeyError
234 
235  assert isinstance(values[0], basestring)
236  return values[0]
237 
238  def error(self, msg):
239  sys.stderr.write(_("package `%s', pin `%s': error: %s\n") % (
240  self.package.refdes, self.number, msg))
241  self.package.netlist.failed = True
242 
243  def warn(self, msg):
244  sys.stderr.write(_("package `%s', pin `%s': warning: %s\n") % (
245  self.package.refdes, self.number, msg))
246 
247 # ============================================================================
248 
249 def postproc_blueprints(netlist):
250  # find components without a refdes
251  for schematic in netlist.schematics:
252  for component in schematic.components:
253  if component.refdes is not None:
254  # component has a refdes -> ok
255  continue
256  if component.is_graphical:
257  # graphical components don't need a refdes -> ok
258  continue
259 
260  # Maybe the symbol isn't a component but a power/gnd symbol?
261 
262  if not component.pins:
263  component.error(_("component has neither refdes nor pins"))
264  continue
265 
266  if not next((True for pin in component.pins
267  if pin.has_netattrib), False):
268  # pin is missing a net= attribute
269  component.error(_(
270  "could not find refdes on component and "
271  "could not find net= attribute on pin"))
272 
273 def postproc_instances(netlist, flat_namespace):
274  netlist.packages = []
275  pkg_dict = {}
276 
277  for component in netlist.components:
278  if component.blueprint.refdes is None:
279  continue
280 
281  if flat_namespace or component.sheet.instantiating_component is None:
282  namespace = None
283  else:
284  namespace = component.sheet
285 
286  try:
287  package = pkg_dict[namespace, component.blueprint.refdes]
288  except KeyError:
289  package = Package(netlist, namespace, component.blueprint.refdes)
290  netlist.packages.append(package)
291  pkg_dict[namespace, component.blueprint.refdes] = package
292 
293  package.components.append(component)
294 
295  for cpin in component.cpins:
296  try:
297  ppin = package.pins_by_number[cpin.blueprint.number]
298  except KeyError:
299  ppin = PackagePin(package, cpin.blueprint.number)
300  package.pins.append(ppin)
301  package.pins_by_number[cpin.blueprint.number] = ppin
302  ppin.cpins.append(cpin)
303 
304  for package in netlist.packages:
305  for ppin in package.pins:
306  nets = []
307  for cpin in ppin.cpins:
308  if cpin.local_net.net not in nets:
309  nets.append(cpin.local_net.net)
310  assert nets
311  if len(nets) > 1:
312  ppin.error(_("multiple nets connected to pin: %s")
313  % _(" vs. ").join(_("\"%s\"") % net.name
314  for net in nets))
315  ppin.net = nets[0]
316 
317  for net in netlist.nets:
318  # walk through the list of components, and through the list
319  # of individual pins on each, adding net names to the list
320  # being careful to ignore duplicates, and unconnected pins
321  net.connections = []
322 
323  # add the net name to the list
324  for cpin in net.component_pins:
325  if cpin.component.blueprint.refdes is None:
326  continue
327  if flat_namespace \
328  or cpin.component.sheet.instantiating_component is None:
329  namespace = None
330  else:
331  namespace = cpin.component.sheet
332  ppin = pkg_dict[namespace, cpin.component.blueprint.refdes] \
333  .pins_by_number[cpin.blueprint.number]
334  if ppin not in net.connections:
335  net.connections.append(ppin)
def get_unique_slots
Return a sorted list of unique slots used by this package.
Definition: package.py:136
def get_attribute
Return the value associated with attribute name on the package.
Definition: package.py:76
def get_all_attributes
Get attribute value(s) from a package with given refdes.
Definition: package.py:51
def get_all_attributes
Returns the appropriate attribute values on this pin.
Definition: package.py:179
def get_pin_by_pinseq
Takes a pinseq string and returns that pinseq pin of this package.
Definition: package.py:98
def get_attribute
Return the value associated with attribute name on the pin.
Definition: package.py:201
def get_slots
Return a sorted list of slots used by this package.
Definition: package.py:117