Merge gnetlist fixes from branch 'xorn'
[geda-gaf.git] / xorn / src / backend / util_repackage.py
blob93a714e90cf3e8269653f7d2c897ea35b4651745
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 ## \file util_repackage.py
21 ## Re-grouping components into packages using a custom refdes function.
23 import sys
24 from gettext import gettext as _
25 import gaf.netlist.package
27 class Package(gaf.netlist.package.Package):
28 def __init__(self, *args, **kwds):
29 gaf.netlist.package.Package.__init__(self, *args, **kwds)
31 def error(self, msg):
32 sys.stderr.write(_("(re-packaged) package `%s': error: %s\n") % (
33 self.refdes, msg))
34 self.netlist.failed = True
36 def warn(self, msg):
37 sys.stderr.write(_("(re-packaged) package `%s': warning: %s\n") % (
38 self.refdes, msg))
40 class PackagePin(gaf.netlist.package.PackagePin):
41 def __init__(self, *args, **kwds):
42 gaf.netlist.package.PackagePin.__init__(self, *args, **kwds)
44 def error(self, msg):
45 sys.stderr.write(
46 _("(re-packaged) package `%s', pin `%s': error: %s\n") % (
47 self.package.refdes, self.number, msg))
48 self.package.netlist.failed = True
50 def warn(self, msg):
51 sys.stderr.write(
52 _("(re-packaged) package `%s', pin `%s': warning: %s\n") % (
53 self.package.refdes, self.number, msg))
55 def blueprint_requires_refdes(component):
56 if component.is_graphical or component.has_netname_attrib \
57 or component.has_portname_attrib:
58 return False
60 for pin in component.pins:
61 if pin.has_netattrib:
62 return False
64 return True
66 ## Re-group components into packages using a custom refdes function.
68 # With the new netlisting code, netlist generation is completely
69 # independent from the backend invocation. Therefore, it is no longer
70 # possible for a backend to override the way \c gnetlist determines
71 # the refdes of a component in order to achieve a different grouping
72 # of components into packages.
74 # This function allows a backend to repeat the grouping stage using a
75 # custom refdes function. It doesn't change the actual netlist but
76 # returns a list of "alternative" package objects which can be used
77 # instead of \c netlist.packages.
79 # \a refdes_func should be a callback function which returns the
80 # desired refdes for a given component instance. In the simplest
81 # case, it would do some kind of transformation on \c
82 # component.blueprint.refdes.
84 def repackage(netlist, refdes_func):
85 new_packages = []
86 pkg_dict = {}
88 for component in netlist.components:
89 new_refdes = refdes_func(component)
91 if new_refdes is None:
92 if blueprint_requires_refdes(component.blueprint):
93 component.warning(_("component dropped during re-packaging"))
94 continue
96 if netlist.flat_package_namespace:
97 namespace = None
98 else:
99 namespace = component.sheet.instantiating_component
101 try:
102 package = pkg_dict[namespace, new_refdes]
103 except KeyError:
104 package = Package(netlist, namespace, new_refdes)
105 new_packages.append(package)
106 pkg_dict[namespace, new_refdes] = package
108 package.components.append(component)
110 for cpin in component.cpins:
111 try:
112 ppin = package.pins_by_number[cpin.blueprint.number]
113 except KeyError:
114 ppin = PackagePin(package, cpin.blueprint.number)
115 package.pins.append(ppin)
116 package.pins_by_number[cpin.blueprint.number] = ppin
117 ppin.cpins.append(cpin)
119 for package in new_packages:
120 for ppin in package.pins:
121 nets = []
122 for cpin in ppin.cpins:
123 if cpin.local_net.net not in nets:
124 nets.append(cpin.local_net.net)
125 assert nets
126 if len(nets) > 1:
127 ppin.error(_("multiple nets connected to pin "
128 "after re-packaging: %s")
129 % _(" vs. ").join(_("\"%s\"") % net.name
130 for net in nets))
131 ppin.net = nets[0]
133 for package in new_packages:
134 if package.namespace is not None:
135 package.refdes = netlist.refdes_mangle_func(
136 package.unmangled_refdes, package.namespace)
137 else:
138 # If refdes mangling is disabled, packages don't have
139 # a sheet attribute, so just use the unmangled refdes.
140 package.refdes = package.unmangled_refdes
142 # compile convenience hash, checking for cross-page name clashes
143 packages_by_refdes = {}
144 for package in new_packages:
145 if package.refdes in packages_by_refdes:
146 other_package = packages_by_refdes[package.refdes]
147 self.error(_("refdes conflict across hierarchy after re-packaging: "
148 "refdes `%s' is used by package `%s' on page "
149 "`%s' and by package `%s' on page `%s'") % (
150 package.refdes,
151 other_package.unmangled_refdes,
152 netlist.refdes_mangle_func('', other_package.namespace),
153 package.unmangled_refdes,
154 netlist.refdes_mangle_func('', package.namespace)))
155 packages_by_refdes[package.refdes] = package
157 return new_packages