1 # -*- coding: utf-8 -*-
2 from __future__
import print_function
9 from Hurricane
import (
10 DbU
, DataBase
, UpdateSession
, Box
, Transformation
, Instance
, Pad
, Pin
,
11 NetExternalComponents
,
13 from plugins
import RSavePlugin
16 class SessionManager(object):
18 Context manager for a GO update session. See Hurricane reference manual
19 for an info on Hurricane::UpdateSession class.
25 def __exit__(self
, *args
):
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
):
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 or tuples of (submodule, x, y), where (x, y) is a submodule's
47 placement point in lambdas,
48 :param pin_width: default pin width,
49 :param pin_height: default pin height,
50 :param pin_suffix: default pin suffix,
51 :param pin_layer: default layer for placing pins,
52 :param north_pins: list of pin configuration dictionaries for placing
53 pins on the north side,
54 :param east_pins: ditto (for the east side),
55 :param south_pins: ditto (for the south side),
56 :param west_pins: ditto (for the west side),
57 :param pads: dictionary of {net: list of layers} for creating pads,
58 :param kwargs: extra parameters to be implemented in derived classes.
61 self
.af
= CRL
.AllianceFramework
.get()
62 self
.db
= DataBase
.getDB()
66 if isinstance(cell
, basestring
):
67 self
.cell
= self
.af
.getCell(cell
, CRL
.Catalog
.State
.Logical
)
71 self
.pin_width
= pin_width
72 self
.pin_height
= pin_height
73 self
.pin_suffix
= pin_suffix
75 self
.pin_layer
= self
.get_layer('METAL3')
76 elif isinstance(pin_layer
, basestring
):
77 self
.pin_layer
= self
.get_layer(pin_layer
)
79 self
.pin_layer
= pin_layer
80 self
.north_pins
= north_pins
or []
81 self
.east_pins
= east_pins
or []
82 self
.south_pins
= south_pins
or []
83 self
.west_pins
= west_pins
or []
85 self
.pads
= pads
or {}
88 if submodules
is not None:
89 for submodule
in submodules
:
90 self
._submodules
.append(
91 (submodule
, None, None) if isinstance(submodule
, Module
)
97 return self
.cell
.getName()
100 def name(self
, name
):
101 self
.cell
.setName(name
)
108 """ The real abutment box. """
109 return self
.cell
.getAbutmentBox()
113 self
.cell
.setAbutmentBox(ab
)
117 """ Cached instances. """
118 if self
._instances
is None:
119 self
._instances
= self
.cell
.getInstances()
121 return self
._instances
123 def get_layer(self
, name
):
124 """ Creates a new layer or returns it from cache. """
125 if name
in self
._layer
_cache
:
126 return self
._layer
_cache
[name
]
128 layer
= self
.db
.getTechnology().getLayer(name
)
129 self
._layer
_cache
[name
] = layer
135 Convert lambdas to database units. (See Hurricane+Python Manual 3.4.)
137 return DbU
.fromLambda(lmb
)
142 Convert lambdas to database units. (See Hurricane+Python Manual 3.4.)
144 return DbU
.toLambda(dbu
)
146 def compute_ab(self
):
147 """ Compute default abutment box without placement. """
148 etesian
= Etesian
.EtesianEngine
.create(self
.cell
)
149 etesian
.setDefaultAb()
153 """ Places the current cell. """
154 etesian
= Etesian
.EtesianEngine
.create(self
.cell
)
158 """ Routes the current cell. """
159 katana
= Katana
.KatanaEngine
.create(self
.cell
)
161 katana
.runGlobalRouter(Katana
.Flags
.NoFlags
)
162 katana
.loadGlobalRouting(Anabatic
.EngineLoadGrByNet
)
163 katana
.layerAssign(Anabatic
.EngineNoNetLayerAssign
)
164 katana
.runNegociate(Katana
.Flags
.NoFlags
)
165 katana
.finalizeLayout()
166 result
= katana
.isDetailedRoutingSuccess()
170 def place_and_route(self
):
171 """ Places and routes. """
175 def create_pin_series(self
, net
, direction
, name
=None,
176 status
=Pin
.PlacementStatus
.FIXED
, layer
=None,
177 x
=None, y
=None, width
=2.0, height
=2.0,
178 repeat
=1, delta
=0.0, external
=True):
180 Creates a pin or a series of pins in a cell.
182 :param net: Hurricane.Net object name or name template, taking a pin
183 enumeration parameter, i. e. pin number,
184 :param name: pin name or name template taking a pin enumeration
185 parameter (net name or template + suffix),
186 :param direction: Pin.Direction value,
187 :param status: Pin.PlacementStatus value (default is FIXED),
188 :param layer: Hurricane.Layer object or name (METAL3),
189 :param x: starting pin position (left to right, 0.0),
190 :param y: starting pin position (bottom to top, 0.0),
191 :param width: pin width (2,0),
192 :param height: pin height (2.0),
193 :param repeat: a number of pins to be placed or an iterable containing
194 pin template parameters (i. e. pin number, 1),
195 :param delta: next pin position offset (0.0),
196 :param external: mark pin as external (yes),
197 :return: tuple of next pin coordinates, or just (x, y), if delta
201 layer
= self
.pin_layer
202 elif isinstance(layer
, basestring
):
203 layer
= self
.get_layer(layer
)
205 if isinstance(repeat
, int):
206 if repeat
> 1 and delta
== 0.0:
208 '{}: you are trying to place pins on each other.'.format(
212 iterator
= range(repeat
)
217 name
= net
+ self
.pin_suffix
220 pin
= Pin
.create(self
.cell
.getNet(net
.format(i
)),
221 name
.format(i
), direction
, status
, layer
,
222 self
.to_dbu(x
), self
.to_dbu(y
),
223 self
.to_dbu(width
), self
.to_dbu(height
))
224 if direction
in (Pin
.Direction
.NORTH
, Pin
.Direction
.SOUTH
):
231 pin
.getNet().setExternal(True)
232 NetExternalComponents
.setExternal(pin
)
237 """ Create the abutment box with object's initial values. """
238 if self
.width
and self
.height
:
240 0, 0, self
.to_dbu(self
.width
), self
.to_dbu(self
.height
)
243 raise Warning('{}: Module size is not set.'.format(self
.name
))
245 def create_pins(self
):
246 """ Creates all pins set on Module object creation. """
249 if direction
== Pin
.Direction
.EAST
:
250 return self
.from_dbu(self
.ab
.getWidth())
251 if direction
== Pin
.Direction
.WEST
:
256 if direction
== Pin
.Direction
.NORTH
:
257 return self
.from_dbu(self
.ab
.getHeight())
258 if direction
== Pin
.Direction
.SOUTH
:
262 for pins
, direction
in (
263 (self
.north_pins
, Pin
.Direction
.NORTH
),
264 (self
.east_pins
, Pin
.Direction
.EAST
),
265 (self
.south_pins
, Pin
.Direction
.SOUTH
),
266 (self
.west_pins
, Pin
.Direction
.WEST
),
268 last_x
= last_y
= 0.0
269 for pin_config
in pins
:
270 net
= pin_config
.pop('net')
271 name
= pin_config
.pop('name', net
+ self
.pin_suffix
)
272 layer
= pin_config
.pop('layer', self
.pin_layer
)
273 x
= pin_config
.pop('x', default_x())
274 y
= pin_config
.pop('y', default_y())
275 last_x
, last_y
= self
.create_pin_series(
276 net
, direction
, name
=name
, layer
=layer
, x
=x
, y
=y
,
279 def create_pads_for_net(self
, net
, layers
):
281 Creates a series of pads for a given net.
283 :param net: net name or Hurricane.Net object to create pads for,
284 :param layers: list of layer names or Hurricane.Layer objects
288 temp_ab
.inflate(self
.to_dbu(-5.0))
289 if isinstance(net
, basestring
):
290 net
= self
.cell
.getNet(net
)
293 if isinstance(layer
, basestring
):
294 layer
= self
.get_layer(layer
)
295 Pad
.create(net
, layer
, temp_ab
)
297 def create_pads(self
):
298 """ Create all pads for a given Module object. """
300 for net
, layers
in self
.pads
.items():
301 self
.create_pads_for_net(net
, layers
)
304 def submodules(self
):
305 """ Submodules iterator. """
306 return iter(submodule
for submodule
, x
, y
in self
._submodules
)
308 def find_submodule(self
, name
):
310 Returns first submodule matching `name`. Better give your submodules
313 :param name: submodule name to match,
314 :return: `Module` object.
316 return next(s
for s
in self
.submodules
if s
.name
== name
)
318 def build_submodules(self
):
320 Execute submodules and gather their status.
322 :return: True if all submodules executed successfully, False otherwise.
325 for submodule
in self
.submodules
:
326 if not submodule
.build():
331 def place_submodule(self
, submodule
, x
, y
):
333 Places a submodule to a given location.
335 :param submodule: `Module` object,
336 :param x: placement coordinate,
337 :param y: placement coordinate.
342 inst
for inst
in self
.instances
if inst
.getName().endswith(
348 instance
.setTransformation(Transformation(
349 self
.to_dbu(x
), self
.to_dbu(y
), Transformation
.Orientation
.ID
351 instance
.setPlacementStatus(Instance
.PlacementStatus
.FIXED
)
353 def place_submodules(self
):
355 Places the submodules in the current module using their initial
356 placement points, if set.
358 for submodule
, x
, y
in self
._submodules
:
359 if x
is not None and y
is not None:
360 self
.place_submodule(submodule
, x
, y
)
363 '{}: cannot place {}, because its '
364 'initial placement point is not set.'
365 ).format(self
.name
, submodule
.name
))
369 RSavePlugin
.ScriptMain(editor
=self
.editor
, cell
=self
.cell
)
372 """ Main routine. """
374 raise NotImplementedError('You need to implement the `build` method.')
379 def __init__(self
, priority
=None):
380 self
._priority
= priority
383 if self
._priority
is not None:
384 Cfg
.Configuration
.pushDefaultPriority(self
._priority
)
387 def __setattr__(self
, attr
, val
):
388 if attr
.startswith("_"):
389 self
.__dict
__[attr
] = val
391 attr
= attr
.replace("_", ".")
392 if isinstance(val
, bool):
393 Cfg
.getParamBool(attr
).setBool(val
)
394 elif isinstance(val
, int):
395 p
= Cfg
.getParamInt(attr
) # all params have a type
396 if p
.type == 'Enumerate':
397 Cfg
.getParamEnumerate(attr
).setInt(val
)
399 Cfg
.getParamInt(attr
).setInt(val
)
401 Cfg
.getParamPercentage(attr
).setPercentage(float(val
[:-1]))
403 Cfg
.getParamString(attr
).setString(val
)
405 def __exit__(self
, *args
):
406 if self
._priority
is not None:
407 Cfg
.Configuration
.popDefaultPriority()