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