1 # -*- coding: utf-8 -*-
2 from __future__
import print_function
10 from Hurricane
import (
11 Breakpoint
, DbU
, DataBase
, UpdateSession
, Box
, Transformation
, Instance
, Pad
, Pin
,
12 NetExternalComponents
,
14 from plugins
import rsave
17 class SessionManager(object):
19 Context manager for a GO update session. See Hurricane reference manual
20 for an info on Hurricane::UpdateSession class.
26 def __exit__(self
, *args
):
35 def __init__(self
, cell
, editor
, width
=None, height
=None, submodules
=None,
36 pin_width
=2.0, pin_height
=2.0, pin_suffix
='.0',
37 pin_layer
=None, north_pins
=None, east_pins
=None,
38 south_pins
=None, west_pins
=None, pads
=None,
39 orientation
=None, **kwargs
):
43 :param cell: cell name or Hurricane.Cell object,
44 :param editor: editor object when executing from cgt (or None),
45 :param width: module width,
46 :param height: module height,
47 :param submodules: submodules (Module objects)
48 or tuples of (submodule, x, y), where (x, y) is a submodule's
49 placement point in lambdas,
50 :param pin_width: default pin width,
51 :param pin_height: default pin height,
52 :param pin_suffix: default pin suffix,
53 :param pin_layer: default layer for placing pins,
54 :param north_pins: list of pin configuration dictionaries for placing
55 pins on the north side,
56 :param east_pins: ditto (for the east side),
57 :param south_pins: ditto (for the south side),
58 :param west_pins: ditto (for the west side),
59 :param pads: dictionary of {net: list of layers} for creating pads,
60 :param orientation: when placed, should be orientated/mirrored etc.
61 :param kwargs: extra parameters to be implemented in derived classes.
64 self
.af
= CRL
.AllianceFramework
.get()
65 self
.db
= DataBase
.getDB()
69 if isinstance(cell
, basestring
):
70 self
.cell
= self
.af
.getCell(cell
, CRL
.Catalog
.State
.Logical
)
74 self
.pin_width
= pin_width
75 self
.pin_height
= pin_height
76 self
.pin_suffix
= pin_suffix
78 self
.pin_layer
= self
.get_layer('METAL3')
79 elif isinstance(pin_layer
, basestring
):
80 self
.pin_layer
= self
.get_layer(pin_layer
)
82 self
.pin_layer
= pin_layer
83 self
.north_pins
= north_pins
or []
84 self
.east_pins
= east_pins
or []
85 self
.south_pins
= south_pins
or []
86 self
.west_pins
= west_pins
or []
88 self
.orientation
= orientation
or Transformation
.Orientation
.ID
90 self
.pads
= pads
or {}
93 if submodules
is not None:
94 for submodule
in submodules
:
95 self
._submodules
.append(
96 (submodule
, None, None) if isinstance(submodule
, Module
)
103 return self
.cell
.getName()
106 def name(self
, name
):
107 self
.cell
.setName(name
)
114 """ The real abutment box. """
115 return self
.cell
.getAbutmentBox()
119 self
.cell
.setAbutmentBox(ab
)
123 """ Cached instances. """
124 if self
._instances
is None:
125 self
._instances
= self
.cell
.getInstances()
127 return self
._instances
129 def get_layer(self
, name
):
130 """ Creates a new layer or returns it from cache. """
131 if name
in self
._layer
_cache
:
132 return self
._layer
_cache
[name
]
134 layer
= self
.db
.getTechnology().getLayer(name
)
135 self
._layer
_cache
[name
] = layer
141 Convert lambdas to database units. (See Hurricane+Python Manual 3.4.)
143 return DbU
.fromLambda(lmb
)
148 Convert lambdas to database units. (See Hurricane+Python Manual 3.4.)
150 return DbU
.toLambda(dbu
)
154 return self
.from_dbu(self
.ab
.getXMin())
158 return self
.from_dbu(self
.ab
.getYMin())
162 return self
.from_dbu(self
.ab
.getWidth())
166 return self
.from_dbu(self
.ab
.getXHeight())
169 def match_instance(datapath_insts
, op
, plug_name
, inst
):
171 Guess the position of an instance from its nets connections,
172 and put it at the right place in the datapath vector.
174 :param datapath_insts: vector of bit slices,
175 :param op: operator name,
176 :param inst: instance to classify,
177 :param plug_name: name of the plug to use to guess the bit index,
178 :return: boolean, True if the instance has been matched.
180 if not inst
.getMasterCell().getName().startswith(op
):
182 re_net_index
= re
.compile(r
'[^(]+\((?P<index>[\d]+)\)$')
183 for plug
in inst
.getPlugs():
184 if plug
.getMasterNet().getName() != plug_name
:
186 m
= re_net_index
.match(plug
.getNet().getName())
189 bit_slice
= datapath_insts
[int(m
.group('index'))]
190 for column
in bit_slice
:
193 print ("match", plug_name
, int(m
.group('index')),
199 def compute_ab(self
):
200 """ Compute default abutment box without placement. """
201 etesian
= Etesian
.EtesianEngine
.create(self
.cell
)
202 etesian
.setDefaultAb()
205 def set_ab(self
, width
, height
):
207 Let the user specify the abutment box. Bottom left corner always
210 self
.cell
.setAbutmentBox(Box(self
.to_dbu(0.0), self
.to_dbu(0.0),
211 self
.to_dbu(width
), self
.to_dbu(height
)))
214 """ Places the current cell. """
215 etesian
= Etesian
.EtesianEngine
.create(self
.cell
)
219 """ Routes the current cell. """
220 katana
= Katana
.KatanaEngine
.create(self
.cell
)
222 katana
.runGlobalRouter(Katana
.Flags
.NoFlags
)
223 katana
.loadGlobalRouting(Anabatic
.EngineLoadGrByNet
)
224 katana
.layerAssign(Anabatic
.EngineNoNetLayerAssign
)
225 katana
.runNegociate(Katana
.Flags
.NoFlags
)
226 #Breakpoint.stop(0, 'After routing {0}'.format(self.cell))
227 katana
.finalizeLayout()
228 result
= katana
.isDetailedRoutingSuccess()
232 def place_and_route(self
):
233 """ Places and routes. """
237 def create_pin_series(self
, net
, direction
, name
=None,
238 status
=Pin
.PlacementStatus
.FIXED
, layer
=None,
239 x
=None, y
=None, width
=2.0, height
=2.0,
240 repeat
=1, delta
=0.0, external
=True):
242 Creates a pin or a series of pins in a cell.
244 :param net: Hurricane.Net object name or name template, taking a pin
245 enumeration parameter, i. e. pin number,
246 :param name: pin name or name template taking a pin enumeration
247 parameter (net name or template + suffix),
248 :param direction: Pin.Direction value,
249 :param status: Pin.PlacementStatus value (default is FIXED),
250 :param layer: Hurricane.Layer object or name (METAL3),
251 :param x: starting pin position (left to right, 0.0),
252 :param y: starting pin position (bottom to top, 0.0),
253 :param width: pin width (2,0),
254 :param height: pin height (2.0),
255 :param repeat: a number of pins to be placed or an iterable containing
256 pin template parameters (i. e. pin number, 1),
257 :param delta: next pin position offset (0.0),
258 :param external: mark pin as external (yes),
259 :return: tuple of next pin coordinates, or just (x, y), if delta
263 layer
= self
.pin_layer
264 elif isinstance(layer
, basestring
):
265 layer
= self
.get_layer(layer
)
267 if isinstance(repeat
, int):
268 if repeat
> 1 and delta
== 0.0:
270 '{}: you are trying to place pins on each other.'.format(
274 iterator
= range(repeat
)
279 name
= net
+ self
.pin_suffix
282 pin
= Pin
.create(self
.cell
.getNet(net
.format(i
)),
283 name
.format(i
), direction
, status
, layer
,
284 self
.to_dbu(x
), self
.to_dbu(y
),
285 self
.to_dbu(width
), self
.to_dbu(height
))
286 if direction
in (Pin
.Direction
.NORTH
, Pin
.Direction
.SOUTH
):
293 pin
.getNet().setExternal(True)
294 NetExternalComponents
.setExternal(pin
)
299 """ Create the abutment box with object's initial values. """
300 if self
.width
and self
.height
:
302 0, 0, self
.to_dbu(self
.width
), self
.to_dbu(self
.height
)
305 raise Warning('{}: Module size is not set.'.format(self
.name
))
307 def create_pins(self
):
308 """ Creates all pins set on Module object creation. """
311 if direction
== Pin
.Direction
.EAST
:
312 return self
.from_dbu(self
.ab
.getWidth())
313 if direction
== Pin
.Direction
.WEST
:
318 if direction
== Pin
.Direction
.NORTH
:
319 return self
.from_dbu(self
.ab
.getHeight())
320 if direction
== Pin
.Direction
.SOUTH
:
324 for pins
, direction
in (
325 (self
.north_pins
, Pin
.Direction
.NORTH
),
326 (self
.east_pins
, Pin
.Direction
.EAST
),
327 (self
.south_pins
, Pin
.Direction
.SOUTH
),
328 (self
.west_pins
, Pin
.Direction
.WEST
),
330 last_x
= last_y
= 0.0
331 for pin_config
in pins
:
332 net
= pin_config
.pop('net')
333 name
= pin_config
.pop('name', net
+ self
.pin_suffix
)
334 layer
= pin_config
.pop('layer', self
.pin_layer
)
335 x
= pin_config
.pop('x', default_x())
336 y
= pin_config
.pop('y', default_y())
337 last_x
, last_y
= self
.create_pin_series(
338 net
, direction
, name
=name
, layer
=layer
, x
=x
, y
=y
,
341 def create_pads_for_net(self
, net
, layers
):
343 Creates a series of pads for a given net.
345 :param net: net name or Hurricane.Net object to create pads for,
346 :param layers: list of layer names or Hurricane.Layer objects
350 temp_ab
.inflate(self
.to_dbu(-5.0))
351 if isinstance(net
, basestring
):
352 net
= self
.cell
.getNet(net
)
355 if isinstance(layer
, basestring
):
356 layer
= self
.get_layer(layer
)
357 Pad
.create(net
, layer
, temp_ab
)
359 def create_pads(self
):
360 """ Create all pads for a given Module object. """
362 for net
, layers
in self
.pads
.items():
363 self
.create_pads_for_net(net
, layers
)
366 def submodules(self
):
367 """ Submodules iterator. """
368 return iter(submodule
for submodule
, x
, y
in self
._submodules
)
370 def find_submodule(self
, name
):
372 Returns first submodule matching `name`. Better give your submodules
375 :param name: submodule name to match,
376 :return: `Module` object.
378 return next(s
for s
in self
.submodules
if s
.name
== name
)
380 def build_submodules(self
):
382 Execute submodules and gather their status.
384 :return: True if all submodules executed successfully, False otherwise.
387 for submodule
in self
.submodules
:
388 if not submodule
.build():
393 def place_submodule(self
, submodule
, x
, y
):
395 Places a submodule to a given location.
397 :param submodule: `Module` object,
398 :param x: placement coordinate,
399 :param y: placement coordinate.
404 inst
for inst
in self
.instances
if inst
.getName().endswith(
410 instance
.setTransformation(Transformation(
411 self
.to_dbu(x
), self
.to_dbu(y
), submodule
.orientation
,
413 instance
.setPlacementStatus(Instance
.PlacementStatus
.FIXED
)
415 def place_submodules(self
):
417 Places the submodules in the current module using their initial
418 placement points, if set.
420 for submodule
, x
, y
in self
._submodules
:
421 if x
is not None and y
is not None:
422 self
.place_submodule(submodule
, x
, y
)
425 '{}: cannot place {}, because its '
426 'initial placement point is not set.'
427 ).format(self
.name
, submodule
.name
))
431 rsave
.scriptMain(editor
=self
.editor
, cell
=self
.cell
)
434 """ Main routine. """
436 raise NotImplementedError('You need to implement the `build` method.')
438 def get_net_connections(self
, to_find
, already_found
):
439 inst
= self
.cell
.getInstances()
440 return get_net_connections(inst
, to_find
, already_found
)
445 def __init__(self
, priority
=None):
446 self
._priority
= priority
449 if self
._priority
is not None:
450 Cfg
.Configuration
.pushDefaultPriority(self
._priority
)
453 def __setattr__(self
, attr
, val
):
454 if attr
.startswith("_"):
455 self
.__dict
__[attr
] = val
457 attr
= attr
.replace("_", ".")
458 if isinstance(val
, bool):
459 Cfg
.getParamBool(attr
).setBool(val
)
460 elif isinstance(val
, int):
461 p
= Cfg
.getParamInt(attr
) # all params have a type
462 if p
.type == 'Enumerate':
463 Cfg
.getParamEnumerate(attr
).setInt(val
)
465 Cfg
.getParamInt(attr
).setInt(val
)
467 Cfg
.getParamPercentage(attr
).setPercentage(float(val
[:-1]))
469 Cfg
.getParamString(attr
).setString(val
)
471 def __exit__(self
, *args
):
472 if self
._priority
is not None:
473 Cfg
.Configuration
.popDefaultPriority()
476 def get_net_connections(instances
, find
, already_found
):
480 for inst
in instances
:
481 if (inst
.getPlacementStatus() !=
482 Instance
.PlacementStatus
.UNPLACED
):
484 #print ("instance", inst)
485 for plug
in inst
.getConnectedPlugs():
486 netname
= plug
.getNet().getName()
487 if netname
in already_found
:
489 if plug
.getNet().getName() in find
:
490 #print ("plug", plug, plug.getNet().getName())
491 for p
in plug
.getNet().getPlugs():
493 if (c
.getPlacementStatus() !=
494 Instance
.PlacementStatus
.UNPLACED
):
496 #print ("notplaced", c)
497 for pc
in c
.getConnectedPlugs():
499 pn
= pc
.getNet().getName()
500 if pn
not in find
and pn
not in already_found
:
501 search_more
.append(pn
)
505 print("more", search_more
)
506 new_found
= find
+ already_found
507 more
= get_net_connections(new
, search_more
, new_found
)