Replace submodule functions with Module objects.
[soclayout.git] / experiments7 / utils.py
1 # -*- coding: utf-8 -*-
2 from __future__ import print_function
3
4 import Anabatic
5 import CRL
6 import Etesian
7 import Katana
8 from Hurricane import (
9 DbU, DataBase, UpdateSession, Box, Transformation, Instance, Pad, Pin,
10 NetExternalComponents,
11 )
12 from plugins import RSavePlugin
13
14
15 class Module:
16
17 _layer_cache = {}
18 _instances = None
19
20 def __init__(self, cell, editor, width=None, height=None, submodules=None,
21 pin_width=2.0, pin_height=2.0, pin_suffix='.0',
22 pin_layer=None, north_pins=None, east_pins=None,
23 south_pins=None, west_pins=None, pads=None, **kwargs):
24 """
25 Creates a module.
26
27 :param cell: cell name or Hurricane.Cell object,
28 :param editor: editor object when executing from cgt (or None),
29 :param width: module width,
30 :param height: module height,
31 :param submodules: submodules (Module objects),
32 :param pin_width: default pin width,
33 :param pin_height: default pin height,
34 :param pin_suffix: default pin suffix,
35 :param pin_layer: default layer for placing pins,
36 :param north_pins: list of pin configuration dictionaries for placing
37 pins on the north side,
38 :param east_pins: ditto (for the east side),
39 :param south_pins: ditto (for the south side),
40 :param west_pins: ditto (for the west side),
41 :param pads: dictionary of {net: list of layers} for creating pads,
42 :param kwargs: extra parameters to be implemented in derived classes.
43 """
44 self.editor = editor
45 self.af = CRL.AllianceFramework.get()
46 self.db = DataBase.getDB()
47 self.width = width
48 self.height = height
49
50 if isinstance(cell, basestring):
51 self.cell = self.af.getCell(cell, CRL.Catalog.State.Logical)
52 else:
53 self.cell = cell
54
55 self.pin_width = pin_width
56 self.pin_height = pin_height
57 self.pin_suffix = pin_suffix
58 if pin_layer is None:
59 self.pin_layer = self.get_layer('METAL3')
60 elif isinstance(pin_layer, basestring):
61 self.pin_layer = self.get_layer(pin_layer)
62 else:
63 self.pin_layer = pin_layer
64 self.north_pins = north_pins or []
65 self.east_pins = east_pins or []
66 self.south_pins = south_pins or []
67 self.west_pins = west_pins or []
68
69 self.pads = pads or {}
70
71 self.submodules = submodules or []
72
73 @property
74 def name(self):
75 return self.cell.getName()
76
77 def __str__(self):
78 return self.name
79
80 @property
81 def ab(self):
82 """ The real abutment box. """
83 return self.cell.getAbutmentBox()
84
85 @ab.setter
86 def ab(self, ab):
87 self.cell.setAbutmentBox(ab)
88
89 @property
90 def instances(self):
91 """ Cached instances. """
92 if self._instances is None:
93 self._instances = self.cell.getInstances()
94
95 return self._instances
96
97 def get_layer(self, name):
98 """ Creates a new layer or returns it from cache. """
99 if name in self._layer_cache:
100 return self._layer_cache[name]
101
102 layer = self.db.getTechnology().getLayer(name)
103 self._layer_cache[name] = layer
104 return layer
105
106 @staticmethod
107 def to_dbu(lmb):
108 """
109 Convert lambdas to database units. (See Hurricane+Python Manual 3.4.)
110 """
111 return DbU.fromLambda(lmb)
112
113 @staticmethod
114 def from_dbu(dbu):
115 """
116 Convert lambdas to database units. (See Hurricane+Python Manual 3.4.)
117 """
118 return DbU.toLambda(dbu)
119
120 def place_and_route(self):
121 """ Places and routes. """
122 UpdateSession.open()
123
124 etesian = Etesian.EtesianEngine.create(self.cell)
125 etesian.place()
126
127 katana = Katana.KatanaEngine.create(self.cell)
128 katana.digitalInit()
129 katana.runGlobalRouter(Katana.Flags.NoFlags)
130 katana.loadGlobalRouting(Anabatic.EngineLoadGrByNet)
131 katana.layerAssign(Anabatic.EngineNoNetLayerAssign)
132 katana.runNegociate(Katana.Flags.NoFlags)
133 katana.finalizeLayout()
134 result = katana.isDetailedRoutingSuccess()
135 katana.destroy()
136
137 UpdateSession.close()
138 return result
139
140 def create_pin_series(self, net, direction, name=None,
141 status=Pin.PlacementStatus.FIXED, layer=None,
142 x=None, y=None, width=2.0, height=2.0,
143 repeat=1, delta=0.0, external=True):
144 """
145 Creates a series of pins in a cell.
146
147 :param net: Hurricane.Net object name or name template, taking a pin
148 enumeration parameter, i. e. pin number,
149 :param name: pin name or name template taking a pin enumeration
150 parameter (net name or template + suffix),
151 :param direction: Pin.Direction value,
152 :param status: Pin.PlacementStatus value (default is FIXED),
153 :param layer: Hurricane.Layer object or name (METAL3),
154 :param x: starting pin position (left to right, 0.0),
155 :param y: starting pin position (bottom to top, 0.0),
156 :param width: pin width (2,0),
157 :param height: pin height (2.0),
158 :param repeat: a number of pins to be placed or an iterable containing
159 pin template parameters (i. e. pin number, 1),
160 :param delta: next pin position offset (0.0),
161 :param external: mark pin as external (yes),
162 :return: tuple of next pin coordinates, or just (x, y), if delta
163 was not provided.
164 """
165 if layer is None:
166 layer = self.pin_layer
167 elif isinstance(layer, basestring):
168 layer = self.get_layer(layer)
169
170 if isinstance(repeat, int):
171 if repeat > 1 and delta == 0.0:
172 raise Warning('You are trying to place pins on each other.')
173 iterator = range(repeat)
174 else:
175 iterator = repeat
176
177 if name is None:
178 name = net + self.pin_suffix
179
180 for i in iterator:
181 pin = Pin.create(self.cell.getNet(net.format(i)),
182 name.format(i), direction, status, layer,
183 self.to_dbu(x), self.to_dbu(y),
184 self.to_dbu(width), self.to_dbu(height))
185 if direction in (Pin.Direction.NORTH, Pin.Direction.SOUTH):
186 x += delta
187 else:
188 # EAST or WEST
189 y += delta
190
191 if external:
192 pin.getNet().setExternal(True)
193 NetExternalComponents.setExternal(pin)
194
195 return x, y
196
197 def init_abutment_box(self):
198 """ Create the abutment box with object's initial values. """
199
200 UpdateSession.open()
201 self.ab = Box(0, 0, self.to_dbu(self.width), self.to_dbu(self.height))
202 UpdateSession.close()
203
204 def create_pins(self):
205 """ Creates all pins set on Module object creation. """
206
207 def default_x():
208 if direction == Pin.Direction.EAST:
209 return self.from_dbu(self.ab.getWidth())
210 if direction == Pin.Direction.WEST:
211 return 0
212 return last_x
213
214 def default_y():
215 if direction == Pin.Direction.NORTH:
216 return self.from_dbu(self.ab.getHeight())
217 if direction == Pin.Direction.SOUTH:
218 return 0
219 return last_y
220
221 UpdateSession.open()
222
223 for pins, direction in (
224 (self.north_pins, Pin.Direction.NORTH),
225 (self.east_pins, Pin.Direction.EAST),
226 (self.south_pins, Pin.Direction.SOUTH),
227 (self.west_pins, Pin.Direction.WEST),
228 ):
229 last_x = last_y = 0.0
230 for pin_config in pins:
231 net = pin_config.pop('net')
232 name = pin_config.pop('name', net + self.pin_suffix)
233 layer = pin_config.pop('layer', self.pin_layer)
234 x = pin_config.pop('x', default_x())
235 y = pin_config.pop('y', default_y())
236 last_x, last_y = self.create_pin_series(
237 net, direction, name=name, layer=layer, x=x, y=y,
238 **pin_config)
239
240 UpdateSession.close()
241
242 def create_pads_for_net(self, net, layers):
243 """
244 Creates a series of pads for a given net.
245
246 :param net: net name or Hurricane.Net object to create pads for,
247 :param layers: list of layer names or Hurricane.Layer objects
248 to create pads on.
249 """
250 temp_ab = self.ab
251 temp_ab.inflate(self.to_dbu(-5.0))
252 if isinstance(net, basestring):
253 net = self.cell.getNet(net)
254
255 for layer in layers:
256 if isinstance(layer, basestring):
257 layer = self.get_layer(layer)
258 Pad.create(net, layer, temp_ab)
259
260 def create_pads(self):
261 """ Create all pads for a given Module object. """
262
263 UpdateSession.open()
264
265 for net, layers in self.pads.items():
266 self.create_pads_for_net(net, layers)
267
268 UpdateSession.close()
269
270 def do_submodules(self):
271 """ Execute submodules and gather their status. """
272
273 for submodule, x, y in self.submodules:
274 # execute submodule
275 if not submodule.do():
276 return False
277
278 return True
279
280 def place_submodules(self):
281 """ Place submodules in the current module. """
282
283 for submodule, x, y in self.submodules:
284 # find instance
285 instance = [
286 inst for inst in self.instances if inst.getName().endswith(
287 submodule.name
288 )
289 ][0]
290
291 # place submodule
292 instance.setTransformation(Transformation(
293 self.to_dbu(x), self.to_dbu(y), Transformation.Orientation.ID
294 ))
295 instance.setPlacementStatus(Instance.PlacementStatus.FIXED)
296
297 def do(self):
298 """ Main routine. """
299
300 if not self.do_submodules():
301 return False
302
303 self.init_abutment_box()
304
305 self.create_pins()
306
307 if self.editor:
308 self.editor.setCell(self.cell)
309
310 result = self.place_and_route()
311
312 self.create_pads()
313
314 RSavePlugin.ScriptMain(editor=self.editor, cell=self.cell)
315 return result