1 # gaf.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-2020 Roland Lutz
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.
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.
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.
20 ## \namespace gaf.netlist.package
21 ## Grouping components with the same refdes into a package.
24 from gettext
import gettext
as _
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
34 self
.pins_by_number
= {}
36 ## Get attribute value(s) from a package with given refdes.
38 # This function returns the values of a specific attribute type
39 # attached to the symbol instances with this package's refdes.
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
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).
49 # \returns a list of attribute values as strings and \c None
51 def get_all_attributes(self
, name
):
52 if not isinstance(name
, basestring
):
55 # search for refdes instances and through the entire list
57 for component
in self
.components
:
59 value
= component
.blueprint
.get_attribute(name
)
63 if component
.sheet
.instantiating_component
is not None:
64 for param_name
, param_value
in \
65 component
.sheet
.instantiating_component \
66 .blueprint
.parameters
.iteritems():
67 value
= value
.replace(
68 '$(%s)' % param_name
, param_value
)
72 ## Return the value associated with attribute \a name on the package.
74 # It actually computes a single value from the full list of values
75 # produced by \ref get_all_attributes.
77 # Returns the value associated with the first symbol instance for
78 # \a refdes which has a matching attribute. If all instances of
79 # \a refdes do not have the same value for \a name and \a name is
80 # not \c "slot", raises an error.
82 def get_attribute(self
, name
, default
= KeyError):
84 for value
in self
.get_all_attributes(name
):
85 if value
is not None and value
not in values
:
89 self
.error(_("attribute conflict for \"%s\": %s") % (
90 name
, _(" vs. ").join(_("\"%s\"") % value
91 for value
in values
)))
95 if default
is not KeyError:
99 assert isinstance(values
[0], basestring
)
102 ## Takes a pinseq string and returns that pinseq pin of this package.
104 def get_pin_by_pinseq(self
, pinseq
):
105 if not isinstance(pinseq
, int):
108 for component
in self
.components
:
110 pin_blueprint
= component
.blueprint
.pins_by_pinseq
[pinseq
]
113 return self
.pins_by_number
[pin_blueprint
.number
]
117 def get_attribute_names(self
, search_inherited
):
118 # search outside the symbol (attached attributes only)
120 for component
in self
.components
:
122 component
.blueprint
.get_attribute_names(search_inherited
):
127 def error(self
, msg
):
128 sys
.stderr
.write(_("package `%s': error: %s\n") % (self
.refdes
, msg
))
129 self
.netlist
.failed
= True
132 sys
.stderr
.write(_("package `%s': warning: %s\n") % (self
.refdes
, msg
))
134 # ============================================================================
137 def __init__(self
, package
, number
):
138 self
.package
= package
142 ## Returns the appropriate attribute values on this pin.
144 # This function returns the values of a specific attribute type
145 # attached to the instances of this pin. For each instance, the
146 # found attribute value is added to the return list. \c None is
147 # added if the instance has no such attribute.
149 # \note The order of the values in the return list is the order of
150 # pin instances within the netlist (the first element is the
151 # value associated with the first pin instance).
153 # \returns a list of attribute values as strings and \c None
155 def get_all_attributes(self
, name
):
156 if not isinstance(name
, basestring
):
160 for cpin
in self
.cpins
:
162 value
= cpin
.blueprint
.get_attribute(name
)
169 ## Return the value associated with attribute \a name on the pin.
171 # It actually computes a single value from the full list of values
172 # produced by \ref get_all_attributes.
174 # If all instances do not have the same value for \a name, raises
177 def get_attribute(self
, name
, default
= KeyError):
178 # Treat "pinnumber" specially: return the value of self.number
179 # which recognizes slotting. For backwards compatibility,
180 # artificial pins do not have a pinnumber.
182 if name
== 'pinnumber':
183 has_real_pins
= False
184 for cpin
in self
.cpins
:
185 if cpin
.blueprint
.ob
is not None:
191 if default
is not KeyError:
196 for value
in self
.get_all_attributes(name
):
197 if value
is not None and value
not in values
:
201 self
.error(_("attribute conflict for \"%s\": %s") % (
202 name
, _(" vs. ").join(_("\"%s\"") % value
203 for value
in values
)))
207 if default
is not KeyError:
211 assert isinstance(values
[0], basestring
)
214 def error(self
, msg
):
215 if self
.package
.refdes
is not None:
217 _("package `%s', pin `%s': error: %s\n") % (
218 self
.package
.refdes
, self
.number
, msg
))
221 _("package `%s' (unmangled), pin `%s': error: %s\n") % (
222 self
.package
.unmangled_refdes
, self
.number
, msg
))
224 self
.package
.netlist
.failed
= True
227 if self
.package
.refdes
is not None:
229 _("package `%s', pin `%s': warning: %s\n") % (
230 self
.package
.refdes
, self
.number
, msg
))
233 _("package `%s' (unmangled), pin `%s': warning: %s\n") % (
234 self
.package
.unmangled_refdes
, self
.number
, msg
))
236 # ============================================================================
238 def postproc_blueprints(netlist
):
239 # find components without a refdes
240 for schematic
in netlist
.schematics
:
241 for component
in schematic
.components
:
242 if component
.refdes
is not None:
243 # component has a refdes -> ok
245 if component
.is_graphical
:
246 # graphical components don't need a refdes -> ok
248 if component
.has_netname_attrib
or component
.has_portname_attrib
:
249 # component is a power symbol or port -> ok
252 # Maybe the symbol isn't a component but a power/gnd symbol?
254 if not component
.pins
:
255 component
.error(_("component has neither refdes nor pins"))
258 if not next((True for pin
in component
.pins
259 if pin
.has_netattrib
), False):
260 # pin is missing a net= attribute
262 "could not find refdes on component and "
263 "could not find net= attribute on pin"))
265 def postproc_instances(netlist
, flat_namespace
):
266 netlist
.packages
= []
269 for component
in netlist
.components
:
270 if component
.blueprint
.refdes
is None:
276 namespace
= component
.sheet
.namespace
279 package
= pkg_dict
[namespace
, component
.blueprint
.refdes
]
281 package
= Package(netlist
, namespace
, component
.blueprint
.refdes
)
282 netlist
.packages
.append(package
)
283 pkg_dict
[namespace
, component
.blueprint
.refdes
] = package
285 package
.components
.append(component
)
287 for cpin
in component
.cpins
:
289 ppin
= package
.pins_by_number
[cpin
.blueprint
.number
]
291 ppin
= PackagePin(package
, cpin
.blueprint
.number
)
292 package
.pins
.append(ppin
)
293 package
.pins_by_number
[cpin
.blueprint
.number
] = ppin
294 ppin
.cpins
.append(cpin
)
296 for package
in netlist
.packages
:
297 for ppin
in package
.pins
:
299 for cpin
in ppin
.cpins
:
300 if cpin
.local_net
.net
not in nets
:
301 nets
.append(cpin
.local_net
.net
)
304 ppin
.error(_("multiple nets connected to pin: %s")
305 % _(" vs. ").join(_("\"%s\"") % net
.name
309 for net
in netlist
.nets
:
310 # walk through the list of components, and through the list
311 # of individual pins on each, adding net names to the list
312 # being careful to ignore duplicates, and unconnected pins
315 # add the net name to the list
316 for cpin
in net
.component_pins
:
317 if cpin
.component
.blueprint
.refdes
is None:
322 namespace
= cpin
.component
.sheet
.namespace
323 ppin
= pkg_dict
[namespace
, cpin
.component
.blueprint
.refdes
] \
324 .pins_by_number
[cpin
.blueprint
.number
]
325 if ppin
not in net
.connections
:
326 net
.connections
.append(ppin
)