from __future__ import print_function
import sys
-import Anabatic
import CRL
import Cfg
-import Etesian
-import Katana
-import clocktree.ClockTree
-from Hurricane import (
- DbU, DataBase, UpdateSession, Box, Transformation, Instance, Pad, Pin,
- NetExternalComponents,
-)
-from helpers import l
-from plugins import RSavePlugin
+from Hurricane import Box
+from Hurricane import Transformation
+from coriolis2.settings import af
+from utils import Module, SessionManager, Config
import symbolic.cmos # do not remove
-af = CRL.AllianceFramework.get()
BIT_WIDTH = 16
-def get_layer(name, layer_cache={}):
- """ Creates a new layer or returns it from cache. """
- if name in layer_cache:
- return layer_cache[name]
-
- layer = DataBase.getDB().getTechnology().getLayer(name)
- layer_cache[name] = layer
- return layer
-
-
-def to_DbU(l):
- """
- Convert lambdas to database units. (See Hurricane+Python Manual 3.4.)
- """
- return DbU.fromLambda(l)
-
-
-def from_DbU(ph):
- """
- Convert database units to lambdas. (See Hurricane+Python Manual 3.4.)
- """
- return DbU.toLambda(ph)
-
-
-def create_pins(cell, net, name, direction,
- status=Pin.PlacementStatus.FIXED, layer=None,
- x=0.0, y=0.0, width=2.0, height=2.0,
- repeat=1, delta=0.0, external=True):
- """Creates a series of pins in a cell.
-
- :param cell: Hurricane.Cell object to place pins onto, or object name,
- :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,
- :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 isinstance(cell, basestring):
- cell = af.getCell(cell, CRL.Catalog.State.Logical)
-
- if layer is None:
- layer = get_layer('METAL3')
- elif isinstance(layer, basestring):
- layer = 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
-
- for i in iterator:
- pin = Pin.create(cell.getNet(net.format(i)), name.format(i),
- direction, status, layer,
- l(x), l(y), l(width), l(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 place_and_route(cell):
- """
- Places and routes.
-
- :param cell: Hurricane.Cell object to operate on,
- :return: True on success, False otherwise.
- """
- etesian = Etesian.EtesianEngine.create(cell)
- etesian.place()
-
- katana = Katana.KatanaEngine.create(cell)
- katana.digitalInit()
- katana.runGlobalRouter(Katana.Flags.NoFlags)
- katana.loadGlobalRouting(Anabatic.EngineLoadGrByNet)
- katana.layerAssign(Anabatic.EngineNoNetLayerAssign)
- katana.runNegociate(Katana.Flags.NoFlags)
- katana.finalizeLayout()
- success = katana.isDetailedRoutingSuccess()
- katana.destroy()
-
- return success
-
-
def coriolis_setup():
- Cfg.Configuration.pushDefaultPriority(Cfg.Parameter.Priority.UserFile)
-
- cellsTop = '~/alliance-check-toolkit/cells'
- env = af.getEnvironment()
- env.addSYSTEM_LIBRARY(library=cellsTop + '/nsxlib',
- mode=CRL.Environment.Prepend)
- env.addSYSTEM_LIBRARY(library=cellsTop + '/mpxlib',
- mode=CRL.Environment.Prepend)
-
- Cfg.getParamBool('misc.catchCore').setBool(False)
- Cfg.getParamBool('misc.info').setBool(False)
- Cfg.getParamBool('misc.paranoid').setBool(False)
- Cfg.getParamBool('misc.bug').setBool(False)
- Cfg.getParamBool('misc.logMode').setBool(True)
- Cfg.getParamBool('misc.verboseLevel1').setBool(True)
- Cfg.getParamBool('misc.verboseLevel2').setBool(True)
- Cfg.getParamEnumerate('etesian.effort').setInt(2)
- Cfg.getParamPercentage('etesian.spaceMargin').setPercentage(10.0)
- Cfg.getParamPercentage('etesian.aspectRatio').setPercentage(100.0)
- Cfg.getParamBool('etesian.uniformDensity').setBool(True)
- Cfg.getParamInt('anabatic.edgeLenght').setInt(24)
- Cfg.getParamInt('anabatic.edgeWidth').setInt(8)
- Cfg.getParamString('anabatic.topRoutingLayer').setString('METAL5')
- Cfg.getParamInt('katana.searchHalo').setInt(30)
- Cfg.getParamInt('katana.eventsLimit').setInt(1000000)
- Cfg.getParamInt('katana.hTracksReservedLocal').setInt(7)
- Cfg.getParamInt('katana.vTracksReservedLocal').setInt(6)
-
- env = af.getEnvironment()
- env.setCLOCK('^clk$|m_clock')
- env.setPOWER('vdd')
- env.setGROUND('vss')
-
- 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)
+ with Config(Cfg.Parameter.Priority.UserFile) as cfg:
+ cfg.misc_catchCore = False
+ cfg.misc_info = False
+ cfg.misc_paranoid = False
+ cfg.misc_bug = False
+ cfg.misc_logMode = True
+ cfg.misc_verboseLevel1 = True
+ cfg.misc_verboseLevel2 = True
+ cfg.etesian_effort = 2
+ cfg.etesian_spaceMargin = "20.0%"
+ cfg.etesian_aspectRatio = "100.0%"
+ cfg.etesian_uniformDensity = True
+ cfg.anabatic_edgeLenght = 24
+ cfg.anabatic_edgeWidth = 8
+ cfg.anabatic_topRoutingLayer = 'METAL5'
+ cfg.katana_searchHalo = 30
+ cfg.katana_eventsLimit = 1000000
+ cfg.katana_hTracksReservedLocal = 7
+ cfg.katana_vTracksReservedLocal = 6
+
+ env = af.getEnvironment()
+ env.setCLOCK('^clk$|m_clock')
+ env.setPOWER('vdd')
+ env.setGROUND('vss')
+
+class AddSub(Module):
-def sub(editor=None, **kwargs):
+ def build(self):
+ """ Main routine. """
- 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')
+ with SessionManager():
+ self.compute_ab()
+ self.create_pins()
- cell = af.getCell('sub', CRL.Catalog.State.Logical)
- print(cell.getNet('a(0)'))
+ if self.editor:
+ self.editor.setCell(self.cell)
- if not cell:
- print('[ERROR] Unable to load cell "alu16.vst", aborting .')
- return False
+ result = self.place_and_route()
- kwargs['cell'] = cell
+ with SessionManager():
+ self.create_pads()
- width = 350.0
- height = 400.0
+ self.save()
+ return result
- 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()
+class ALU16(Module):
- 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()
+ def save(self):
+ self.name = self.name + '_r'
+ self.af.saveCell(self.cell, CRL.Catalog.State.Views)
+ super(ALU16, self).save()
- RSavePlugin.ScriptMain(editor=editor, **kwargs)
+ def build(self):
+ h_margin = 25.0
+ v_margin = 10.0
-def alu16(editor=None, **kwargs):
+ if not self.build_submodules():
+ return False
- db = DataBase.getDB()
- print(db, dir(db))
- METAL2 = get_layer('METAL2')
- METAL3 = get_layer('METAL3')
+ # at this point we have the (auto-calculated) submodules' dimensions
+ # in their `ab` properties.
- 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
+ add, sub = self.submodules
- width, height = 1100.0, 600.0
- ab = Box(l(0.0), l(0.0), l(width), l(height))
+ with SessionManager():
+ self.compute_ab()
- UpdateSession.open()
- cell.setAbutmentBox(ab)
+ width = self.from_dbu(
+ self.ab.getWidth() + add.ab.getWidth() + sub.ab.getWidth()
+ ) + 4*h_margin
+ height = self.from_dbu(max([
+ self.ab.getHeight(), add.ab.getHeight(), sub.ab.getHeight()
+ ])) + 2*v_margin
- # get instances inside cell
- instances = cell.getInstances()
+ # experiment, over-ride
+ width = 1300
+ height = 370
- # find adder instance
- add_inst = [x for x in instances if x.getName().endswith('add')][0]
- add_inst.setTransformation(Transformation(to_DbU(25.0), to_DbU(75.0),
- Transformation.Orientation.ID))
- add_inst.setPlacementStatus(Instance.PlacementStatus.FIXED)
+ self.ab = Box(0, 0, self.to_dbu(width), self.to_dbu(height))
- # find subtractor instance
- sub_inst = [x for x in instances if x.getName().endswith('sub')][0]
- sub_inst.setTransformation(Transformation(to_DbU(725.0), to_DbU(75.0),
- Transformation.Orientation.ID))
- sub_inst.setPlacementStatus(Instance.PlacementStatus.FIXED)
+ add_wid = self.from_dbu(add.ab.getWidth())
+ sub_ht = self.from_dbu(sub.ab.getHeight())
+ self.place_submodule(add, h_margin, v_margin+add_wid)
+ self.place_submodule(sub, width-sub.ab_width-h_margin+sub_ht-45,
+ v_margin)
- y_north = cell.getAbutmentBox().getYMax()
- create_pins(cell, 'a({})', 'a({}).0', Pin.Direction.SOUTH,
- x=50.0, y=0.0, delta=60.0, repeat=BIT_WIDTH)
- create_pins(cell, 'b({})', 'b({}).0', Pin.Direction.SOUTH,
- x=80.0, y=0.0, delta=60.0, repeat=BIT_WIDTH)
- create_pins(cell, 'o({})', 'o({}).0', Pin.Direction.NORTH,
- x=50.0, y=from_DbU(y_north),
- delta=60.0, repeat=BIT_WIDTH)
- create_pins(cell, 'rst', 'rst.0', Pin.Direction.WEST, layer=METAL2,
- x=0.0, y=140.0)
- UpdateSession.close()
+ # TODO: replace with some form of lazy evaluation?
+ y_north = self.from_dbu(self.ab.getYMax())
+ for pin_conf in self.north_pins:
+ pin_conf['y'] = y_north
- if editor:
- editor.setCell(cell)
+ self.create_pins()
- print("editor", editor, dir(editor))
+ if self.editor:
+ self.editor.setCell(self.cell)
- # place first (in middle, between two)
- # this puts all the remaining cells (little ones)
- # into this (small) space so that they do not go
- # "all over the place" around the add and sub
- ab2 = Box(l(400.0), l(50.0), l(700.0), l(500.0))
+ # place first (in middle, between two)
+ # this puts all the remaining cells (little ones)
+ # into this (small) space so that they do not go
+ # "all over the place" around the add and sub
- cell.setAbutmentBox(ab2)
- etesian = Etesian.EtesianEngine.create(cell)
- etesian.place()
+ # XXX this doesn't work: box is far too big, covers the entire
+ # area (including "under" the add and sub)
+ self.ab = Box(
+ self.to_dbu((width-self.ab_width)/2 - h_margin),
+ self.to_dbu(v_margin),
+ self.to_dbu((width+self.ab_width)/2 + h_margin),
+ self.to_dbu(height - v_margin)
+ )
+ self.ab = Box(self.to_dbu(450), self.to_dbu(15),
+ self.to_dbu(835), self.to_dbu(370))
+ self.place() # place only
- # then route (globally)
- # this connects up not just in the remaining (little) cells,
- # it connects *to add and sub and the outside world as well*
- cell.setAbutmentBox(ab)
+ # then route (globally)
+ # this connects up not just in the remaining (little) cells,
+ # it connects *to add and sub and the outside world as well*
+ self.ab = Box(0, 0, self.to_dbu(width), self.to_dbu(height))
+ result = self.route()
- result = place_and_route(cell)
+ self.save()
+ return result
- af.saveCell(cell, CRL.Catalog.State.Views)
- RSavePlugin.ScriptMain(editor=editor, **kwargs)
- return result
+def ScriptMain(editor=None, **kwargs):
+ coriolis_setup()
+ add = AddSub(
+ 'add', editor,
+ north_pins=[
+ {'net': 'a({})', 'x': 165.0, 'delta': -10.0, 'repeat': BIT_WIDTH},
+ {'net': 'b({})', 'x': 160.0, 'delta': -10.0, 'repeat': BIT_WIDTH},
+ {'net': 'o({})', 'x': 340.0, 'delta': -10.0, 'repeat': BIT_WIDTH},
+ ],
+ south_pins=[
+ ],
+ pads={
+ 'b({})'.format(BIT_WIDTH-1): (
+ 'BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4',
+ ),
+ },
+ orientation=Transformation.Orientation.R3,
+ )
+ sub = AddSub(
+ 'sub', editor,
+ north_pins=[
+ {'net': 'a({})', 'x': 180.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ {'net': 'b({})', 'x': 185.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ {'net': 'o({})', 'x': 10.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ ],
+ south_pins=[
+ ],
+ pads={
+ 'b({})'.format(BIT_WIDTH-1): (
+ 'BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4',
+ ),
+ },
+ orientation=Transformation.Orientation.R1,
+ )
-def ScriptMain(**kwargs):
- coriolis_setup()
- add(**kwargs)
- sub(**kwargs)
- return alu16(**kwargs)
+ alu16 = ALU16(
+ 'alu16', editor, submodules=[add, sub],
+ north_pins=[
+ {'net': 'o({})', 'x': 500.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ {'net': 'op'},
+ ],
+ south_pins=[
+ {'net': 'a({})', 'x': 500.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ {'net': 'b({})', 'x': 700.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ ],
+ west_pins=[
+ {'net': 'rst', 'y': 140.0, 'layer': 'METAL2'},
+ ],
+ )
+ return alu16.build()
if __name__ == '__main__':