import Cfg
import Etesian
import Katana
-import clocktree.ClockTree
from Hurricane import (
- DbU, DataBase, UpdateSession, Box, Transformation, Instance, Pad, Pin,
+ DbU, DataBase, UpdateSession, Box, Transformation, Instance, Pin,
NetExternalComponents,
)
from helpers import l
from plugins import RSavePlugin
+from coriolis2.settings import af
+from utils import Module
import symbolic.cmos # do not remove
-af = CRL.AllianceFramework.get()
BIT_WIDTH = 16
Cfg.Configuration.popDefaultPriority()
-def add(editor=None, **kwargs):
-
- db = DataBase.getDB()
- print(db, dir(db))
- METAL2 = get_layer('METAL2')
- METAL3 = get_layer('METAL3')
- METAL5 = get_layer('METAL5')
- BLOCKAGE2 = get_layer('BLOCKAGE2')
- BLOCKAGE3 = get_layer('BLOCKAGE3')
- BLOCKAGE4 = get_layer('BLOCKAGE4')
- BLOCKAGE5 = get_layer('BLOCKAGE5')
-
- cell = af.getCell('add', CRL.Catalog.State.Logical)
- print(cell.getNet('a(0)'))
-
- if not cell:
- print('[ERROR] Unable to load cell "add.vst", aborting .')
- return False
-
- kwargs['cell'] = cell
-
- width = 350.0
- height = 400.0
-
- ab = Box(l(0.0), l(0.0), l(width), l(height))
-
- cell_gauge = af.getCellGauge()
- margin_as_percentage = Cfg.getParamPercentage(
- 'etesian.spaceMargin'
- ).asPercentage()
- space_margin = (margin_as_percentage + 5) / 100.0
- aspect_ratio = margin_as_percentage / 100.0
- clocktree.ClockTree.computeAbutmentBox(
- cell, space_margin, aspect_ratio, cell_gauge,
- )
- ab2 = cell.getAbutmentBox()
- print("box", ab, ab.getHeight(), ab.getWidth())
- print("calc box", ab2, ab2.getHeight(), ab2.getWidth())
-
- UpdateSession.open()
- cell.setAbutmentBox(ab)
-
- create_pins(cell, 'a({})', 'a({}).0', Pin.Direction.NORTH,
- x=10.0, y=height, delta=20.0, repeat=BIT_WIDTH)
- create_pins(cell, 'o({})', 'o({}).0', Pin.Direction.SOUTH,
- x=100.0, y=0.0, delta=10.0, repeat=BIT_WIDTH)
- create_pins(cell, 'b({})', 'b({}).0', Pin.Direction.NORTH,
- x=20.0, y=height, delta=20.0, repeat=BIT_WIDTH)
- UpdateSession.close()
-
- if editor:
- editor.setCell(cell)
-
- place_and_route(cell)
-
- UpdateSession.open()
-
- ab = cell.getAbutmentBox()
- ab.inflate(to_DbU(-5.0))
-
- # do we really want to use net b(15)?
- last_net = cell.getNet('b({})'.format(BIT_WIDTH-1))
- Pad.create(last_net, BLOCKAGE2, ab)
- Pad.create(last_net, BLOCKAGE3, ab)
- Pad.create(last_net, BLOCKAGE4, ab)
- UpdateSession.close()
-
- RSavePlugin.ScriptMain(editor=editor, **kwargs)
-
-
-def sub(editor=None, **kwargs):
-
- db = DataBase.getDB()
- print(db, dir(db))
- METAL2 = get_layer('METAL2')
- METAL3 = get_layer('METAL3')
- METAL5 = get_layer('METAL5')
- BLOCKAGE2 = get_layer('BLOCKAGE2')
- BLOCKAGE3 = get_layer('BLOCKAGE3')
- BLOCKAGE4 = get_layer('BLOCKAGE4')
- BLOCKAGE5 = get_layer('BLOCKAGE5')
-
- cell = af.getCell('sub', CRL.Catalog.State.Logical)
- print(cell.getNet('a(0)'))
-
- if not cell:
- print('[ERROR] Unable to load cell "alu16.vst", aborting .')
- return False
-
- kwargs['cell'] = cell
-
- width = 350.0
- height = 400.0
-
- ab = Box(l(0.0), l(0.0), l(width), l(height))
-
- cellGauge = af.getCellGauge()
- margin_as_percentage = Cfg.getParamPercentage(
- 'etesian.spaceMargin'
- ).asPercentage()
- spaceMargin = (margin_as_percentage + 5) / 100.0
- aspectRatio = margin_as_percentage / 100.0
- clocktree.ClockTree.computeAbutmentBox(
- cell, spaceMargin, aspectRatio, cellGauge,
- )
- ab2 = cell.getAbutmentBox()
- print("box", ab, ab.getHeight(), ab.getWidth())
- print("calc box", ab2, ab2.getHeight(), ab2.getWidth())
-
- UpdateSession.open()
- cell.setAbutmentBox(ab)
-
- create_pins(cell, 'a({})', 'a({}).0', Pin.Direction.NORTH,
- x=10.0, y=height, delta=20.0, repeat=BIT_WIDTH)
- create_pins(cell, 'o({})', 'o({}).0', Pin.Direction.SOUTH,
- x=100.0, y=0.0, delta=10.0, repeat=BIT_WIDTH)
- create_pins(cell, 'b({})', 'b({}).0', Pin.Direction.NORTH,
- x=20.0, y=height, delta=20.0, repeat=BIT_WIDTH)
-
- UpdateSession.close()
-
- if editor:
- editor.setCell(cell)
-
- place_and_route(cell)
-
- UpdateSession.open()
-
- ab = cell.getAbutmentBox()
- ab.inflate(to_DbU(-5.0))
- # do we really want to use net b(15)?
- last_net = cell.getNet('b({})'.format(BIT_WIDTH-1))
- Pad.create(last_net, BLOCKAGE2, ab)
- Pad.create(last_net, BLOCKAGE3, ab)
- Pad.create(last_net, BLOCKAGE4, ab)
- UpdateSession.close()
-
- RSavePlugin.ScriptMain(editor=editor, **kwargs)
-
-
def alu16(editor=None, **kwargs):
db = DataBase.getDB()
print(db, dir(db))
METAL2 = get_layer('METAL2')
- METAL3 = get_layer('METAL3')
cell = af.getCell('alu16', CRL.Catalog.State.Logical)
if not cell:
print('[ERROR] Unable to load cell "alu16.vst", aborting .')
return False
- kwargs['cell'] = cell
width, height = 1100.0, 600.0
ab = Box(l(0.0), l(0.0), l(width), l(height))
cell.setName(cell.getName()+'_r')
af.saveCell(cell, CRL.Catalog.State.Views)
- RSavePlugin.ScriptMain(editor=editor, **kwargs)
+ RSavePlugin.ScriptMain(editor=editor, cell=cell, **kwargs)
return result
-def ScriptMain(**kwargs):
+def ScriptMain(editor=None, **kwargs):
coriolis_setup()
- add(**kwargs)
- sub(**kwargs)
- return alu16(**kwargs)
+
+ add = Module(
+ 'add', editor, width=350.0, height=400.0,
+ north_pins=[
+ {'net': 'a({})', 'x': 10.0, 'delta': 20.0, 'repeat': BIT_WIDTH},
+ {'net': 'b({})', 'x': 20.0, 'delta': 20.0, 'repeat': BIT_WIDTH},
+ ],
+ south_pins=[
+ {'net': 'o({})', 'x': 100.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ ],
+ pads={'b(15)': ('BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4')},
+ )
+
+ sub = Module(
+ 'sub', editor, width=350.0, height=400.0,
+ north_pins=[
+ {'net': 'a({})', 'x': 10.0, 'delta': 20.0, 'repeat': BIT_WIDTH},
+ {'net': 'b({})', 'x': 20.0, 'delta': 20.0, 'repeat': BIT_WIDTH},
+ ],
+ south_pins=[
+ {'net': 'o({})', 'x': 100.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ ],
+ pads={'b(15)': ('BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4')},
+ )
+
+ add.do()
+ sub.do()
+ return alu16(editor, **kwargs)
if __name__ == '__main__':
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import print_function
+
+import Anabatic
+import CRL
+import Etesian
+import Katana
+from Hurricane import (
+ DbU, DataBase, UpdateSession, Box, Transformation, Instance, Pad, Pin,
+ NetExternalComponents,
+)
+from plugins import RSavePlugin
+
+
+class Module:
+
+ _layer_cache = {}
+ _instances = None
+
+ 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):
+ """
+ Creates a module.
+
+ :param cell: cell name or Hurricane.Cell 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 pin_width: default pin width,
+ :param pin_height: default pin height,
+ :param pin_suffix: default pin suffix,
+ :param pin_layer: default layer for placing pins,
+ :param north_pins: list of pin configuration dictionaries for placing
+ pins on the north side,
+ :param east_pins: ditto (for the east side),
+ :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 kwargs: extra parameters to be implemented in derived classes.
+ """
+ self.editor = editor
+ self.af = CRL.AllianceFramework.get()
+ self.db = DataBase.getDB()
+ self.width = width
+ self.height = height
+
+ if isinstance(cell, basestring):
+ self.cell = self.af.getCell(cell, CRL.Catalog.State.Logical)
+ else:
+ self.cell = cell
+
+ self.pin_width = pin_width
+ self.pin_height = pin_height
+ self.pin_suffix = pin_suffix
+ if pin_layer is None:
+ self.pin_layer = self.get_layer('METAL3')
+ elif isinstance(pin_layer, basestring):
+ self.pin_layer = self.get_layer(pin_layer)
+ else:
+ self.pin_layer = pin_layer
+ self.north_pins = north_pins or []
+ self.east_pins = east_pins or []
+ self.south_pins = south_pins or []
+ self.west_pins = west_pins or []
+
+ self.pads = pads or {}
+
+ self.submodules = submodules or []
+
+ @property
+ def name(self):
+ return self.cell.getName()
+
+ def __str__(self):
+ return self.name
+
+ @property
+ def ab(self):
+ """ The real abutment box. """
+ return self.cell.getAbutmentBox()
+
+ @ab.setter
+ def ab(self, ab):
+ self.cell.setAbutmentBox(ab)
+
+ @property
+ def instances(self):
+ """ Cached instances. """
+ if self._instances is None:
+ self._instances = self.cell.getInstances()
+
+ return self._instances
+
+ def get_layer(self, name):
+ """ Creates a new layer or returns it from cache. """
+ if name in self._layer_cache:
+ return self._layer_cache[name]
+
+ layer = self.db.getTechnology().getLayer(name)
+ self._layer_cache[name] = layer
+ return layer
+
+ @staticmethod
+ def to_dbu(lmb):
+ """
+ Convert lambdas to database units. (See Hurricane+Python Manual 3.4.)
+ """
+ return DbU.fromLambda(lmb)
+
+ @staticmethod
+ def from_dbu(dbu):
+ """
+ Convert lambdas to database units. (See Hurricane+Python Manual 3.4.)
+ """
+ return DbU.toLambda(dbu)
+
+ def place_and_route(self):
+ """ Places and routes. """
+ UpdateSession.open()
+
+ etesian = Etesian.EtesianEngine.create(self.cell)
+ etesian.place()
+
+ katana = Katana.KatanaEngine.create(self.cell)
+ katana.digitalInit()
+ katana.runGlobalRouter(Katana.Flags.NoFlags)
+ katana.loadGlobalRouting(Anabatic.EngineLoadGrByNet)
+ katana.layerAssign(Anabatic.EngineNoNetLayerAssign)
+ katana.runNegociate(Katana.Flags.NoFlags)
+ katana.finalizeLayout()
+ result = katana.isDetailedRoutingSuccess()
+ katana.destroy()
+
+ UpdateSession.close()
+ return result
+
+ def create_pin_series(self, net, direction, name=None,
+ status=Pin.PlacementStatus.FIXED, layer=None,
+ x=None, y=None, width=2.0, height=2.0,
+ repeat=1, delta=0.0, external=True):
+ """
+ Creates a series of pins in a cell.
+
+ :param net: Hurricane.Net object name or name template, taking a pin
+ enumeration parameter, i. e. pin number,
+ :param name: pin name or name template taking a pin enumeration
+ parameter (net name or template + suffix),
+ :param direction: Pin.Direction value,
+ :param status: Pin.PlacementStatus value (default is FIXED),
+ :param layer: Hurricane.Layer object or name (METAL3),
+ :param x: starting pin position (left to right, 0.0),
+ :param y: starting pin position (bottom to top, 0.0),
+ :param width: pin width (2,0),
+ :param height: pin height (2.0),
+ :param repeat: a number of pins to be placed or an iterable containing
+ pin template parameters (i. e. pin number, 1),
+ :param delta: next pin position offset (0.0),
+ :param external: mark pin as external (yes),
+ :return: tuple of next pin coordinates, or just (x, y), if delta
+ was not provided.
+ """
+ if layer is None:
+ layer = self.pin_layer
+ elif isinstance(layer, basestring):
+ layer = self.get_layer(layer)
+
+ if isinstance(repeat, int):
+ if repeat > 1 and delta == 0.0:
+ raise Warning('You are trying to place pins on each other.')
+ iterator = range(repeat)
+ else:
+ iterator = repeat
+
+ if name is None:
+ name = net + self.pin_suffix
+
+ for i in iterator:
+ pin = Pin.create(self.cell.getNet(net.format(i)),
+ name.format(i), direction, status, layer,
+ self.to_dbu(x), self.to_dbu(y),
+ self.to_dbu(width), self.to_dbu(height))
+ if direction in (Pin.Direction.NORTH, Pin.Direction.SOUTH):
+ x += delta
+ else:
+ # EAST or WEST
+ y += delta
+
+ if external:
+ pin.getNet().setExternal(True)
+ NetExternalComponents.setExternal(pin)
+
+ return x, y
+
+ def init_abutment_box(self):
+ """ Create the abutment box with object's initial values. """
+
+ UpdateSession.open()
+ self.ab = Box(0, 0, self.to_dbu(self.width), self.to_dbu(self.height))
+ UpdateSession.close()
+
+ def create_pins(self):
+ """ Creates all pins set on Module object creation. """
+
+ def default_x():
+ if direction == Pin.Direction.EAST:
+ return self.from_dbu(self.ab.getWidth())
+ if direction == Pin.Direction.WEST:
+ return 0
+ return last_x
+
+ def default_y():
+ if direction == Pin.Direction.NORTH:
+ return self.from_dbu(self.ab.getHeight())
+ if direction == Pin.Direction.SOUTH:
+ return 0
+ return last_y
+
+ UpdateSession.open()
+
+ for pins, direction in (
+ (self.north_pins, Pin.Direction.NORTH),
+ (self.east_pins, Pin.Direction.EAST),
+ (self.south_pins, Pin.Direction.SOUTH),
+ (self.west_pins, Pin.Direction.WEST),
+ ):
+ last_x = last_y = 0.0
+ for pin_config in pins:
+ net = pin_config.pop('net')
+ name = pin_config.pop('name', net + self.pin_suffix)
+ layer = pin_config.pop('layer', self.pin_layer)
+ x = pin_config.pop('x', default_x())
+ y = pin_config.pop('y', default_y())
+ last_x, last_y = self.create_pin_series(
+ net, direction, name=name, layer=layer, x=x, y=y,
+ **pin_config)
+
+ UpdateSession.close()
+
+ def create_pads_for_net(self, net, layers):
+ """
+ Creates a series of pads for a given net.
+
+ :param net: net name or Hurricane.Net object to create pads for,
+ :param layers: list of layer names or Hurricane.Layer objects
+ to create pads on.
+ """
+ temp_ab = self.ab
+ temp_ab.inflate(self.to_dbu(-5.0))
+ if isinstance(net, basestring):
+ net = self.cell.getNet(net)
+
+ for layer in layers:
+ if isinstance(layer, basestring):
+ layer = self.get_layer(layer)
+ Pad.create(net, layer, temp_ab)
+
+ def create_pads(self):
+ """ Create all pads for a given Module object. """
+
+ UpdateSession.open()
+
+ for net, layers in self.pads.items():
+ self.create_pads_for_net(net, layers)
+
+ UpdateSession.close()
+
+ def do_submodules(self):
+ """ Execute submodules and gather their status. """
+
+ for submodule, x, y in self.submodules:
+ # execute submodule
+ if not submodule.do():
+ return False
+
+ return True
+
+ def place_submodules(self):
+ """ Place submodules in the current module. """
+
+ for submodule, x, y in self.submodules:
+ # 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)
+
+ def do(self):
+ """ Main routine. """
+
+ if not self.do_submodules():
+ return False
+
+ self.init_abutment_box()
+
+ self.create_pins()
+
+ if self.editor:
+ self.editor.setCell(self.cell)
+
+ result = self.place_and_route()
+
+ self.create_pads()
+
+ RSavePlugin.ScriptMain(editor=self.editor, cell=self.cell)
+ return result