sort-of got layout positions ok
[soclayout.git] / experiments7 / utils.py
index 60057f63810942bcfce160234db1c9eafe0ba5ba..04f9cdea684e6051f48d7919230a4b8af616e91f 100644 (file)
@@ -34,7 +34,8 @@ class Module(object):
     def __init__(self, cell, editor, width=None, height=None, submodules=None,
                  pin_width=2.0, pin_height=2.0, pin_suffix='.0',
                  pin_layer=None, north_pins=None, east_pins=None,
-                 south_pins=None, west_pins=None, pads=None, **kwargs):
+                 south_pins=None, west_pins=None, pads=None,
+                 orientation=None, **kwargs):
         """
         Creates a module.
 
@@ -42,7 +43,9 @@ class Module(object):
         :param editor: editor object when executing from cgt (or None),
         :param width: module width,
         :param height: module height,
-        :param submodules: submodules (Module objects),
+        :param submodules: submodules (Module objects)
+          or tuples of (submodule, x, y), where (x, y) is a submodule's
+          placement point in lambdas,
         :param pin_width: default pin width,
         :param pin_height: default pin height,
         :param pin_suffix: default pin suffix,
@@ -53,6 +56,7 @@ class Module(object):
         :param south_pins: ditto (for the south side),
         :param west_pins: ditto (for the west side),
         :param pads: dictionary of {net: list of layers} for creating pads,
+        :param orientation: when placed, should be orientated/mirrored etc.
         :param kwargs: extra parameters to be implemented in derived classes.
         """
         self.editor = editor
@@ -80,9 +84,18 @@ class Module(object):
         self.south_pins = south_pins or []
         self.west_pins = west_pins or []
 
+        self.orientation = orientation or Transformation.Orientation.ID
+
         self.pads = pads or {}
 
-        self.submodules = submodules or []
+        self._submodules = []
+        if submodules is not None:
+            for submodule in submodules:
+                self._submodules.append(
+                    (submodule, None, None) if isinstance(submodule, Module)
+                    else submodule
+                )
+
 
     @property
     def name(self):
@@ -135,6 +148,28 @@ class Module(object):
         """
         return DbU.toLambda(dbu)
 
+    @property
+    def ab_x(self):
+        return self.from_dbu(self.ab.getXMin())
+
+    @property
+    def ab_y(self):
+        return self.from_dbu(self.ab.getYMin())
+
+    @property
+    def ab_width(self):
+        return self.from_dbu(self.ab.getWidth())
+
+    @property
+    def ab_height(self):
+        return self.from_dbu(self.ab.getXHeight())
+
+    def compute_ab(self):
+        """ Compute default abutment box without placement. """
+        etesian = Etesian.EtesianEngine.create(self.cell)
+        etesian.setDefaultAb()
+        etesian.destroy()
+
     def place(self):
         """ Places the current cell. """
         etesian = Etesian.EtesianEngine.create(self.cell)
@@ -190,7 +225,11 @@ class Module(object):
 
         if isinstance(repeat, int):
             if repeat > 1 and delta == 0.0:
-                raise Warning('You are trying to place pins on each other.')
+                raise Warning(
+                    '{}: you are trying to place pins on each other.'.format(
+                        self.name
+                    )
+                )
             iterator = range(repeat)
         else:
             iterator = repeat
@@ -215,10 +254,14 @@ class Module(object):
 
         return x, y
 
-    def init_abutment_box(self):
+    def init_ab(self):
         """ Create the abutment box with object's initial values. """
-
-        self.ab = Box(0, 0, self.to_dbu(self.width), self.to_dbu(self.height))
+        if self.width and self.height:
+            self.ab = Box(
+                0, 0, self.to_dbu(self.width), self.to_dbu(self.height)
+            )
+        else:
+            raise Warning('{}: Module size is not set.'.format(self.name))
 
     def create_pins(self):
         """ Creates all pins set on Module object creation. """
@@ -278,6 +321,21 @@ class Module(object):
         for net, layers in self.pads.items():
             self.create_pads_for_net(net, layers)
 
+    @property
+    def submodules(self):
+        """ Submodules iterator. """
+        return iter(submodule for submodule, x, y in self._submodules)
+
+    def find_submodule(self, name):
+        """
+        Returns first submodule matching `name`. Better give your submodules
+        unique names.
+
+        :param name: submodule name to match,
+        :return: `Module` object.
+        """
+        return next(s for s in self.submodules if s.name == name)
+
     def build_submodules(self):
         """
         Execute submodules and gather their status.
@@ -285,28 +343,47 @@ class Module(object):
         :return: True if all submodules executed successfully, False otherwise.
         """
 
-        for submodule, x, y in self.submodules:
+        for submodule in self.submodules:
             if not submodule.build():
                 return False
 
         return True
 
-    def place_submodules(self):
-        """ Place submodules in the current module. """
+    def place_submodule(self, submodule, x, y):
+        """
+        Places a submodule to a given location.
 
-        for submodule, x, y in self.submodules:
-            # find instance
-            instance = [
-                inst for inst in self.instances if inst.getName().endswith(
-                    submodule.name
-                )
-            ][0]
+        :param submodule: `Module` object,
+        :param x: placement coordinate,
+        :param y: placement coordinate.
+        """
+
+        # find instance
+        instance = [
+            inst for inst in self.instances if inst.getName().endswith(
+                submodule.name
+            )
+        ][0]
 
-            # place submodule
-            instance.setTransformation(Transformation(
-                self.to_dbu(x), self.to_dbu(y), Transformation.Orientation.ID
-            ))
-            instance.setPlacementStatus(Instance.PlacementStatus.FIXED)
+        # place submodule
+        instance.setTransformation(Transformation(
+            self.to_dbu(x), self.to_dbu(y), submodule.orientation,
+        ))
+        instance.setPlacementStatus(Instance.PlacementStatus.FIXED)
+
+    def place_submodules(self):
+        """
+        Places the submodules in the current module using their initial
+        placement points, if set.
+        """
+        for submodule, x, y in self._submodules:
+            if x is not None and y is not None:
+                self.place_submodule(submodule, x, y)
+            else:
+                raise Warning((
+                    '{}: cannot place {}, because its '
+                    'initial placement point is not set.'
+                ).format(self.name, submodule.name))
 
     def save(self):
         """ Saves cell. """
@@ -317,6 +394,7 @@ class Module(object):
 
         raise NotImplementedError('You need to implement the `build` method.')
 
+
 class Config:
 
     def __init__(self, priority=None):