from __future__ import print_function
import sys
-import Anabatic
import CRL
import Cfg
-import Etesian
-import Katana
-import clocktree.ClockTree
-from chip import Configuration
-from Hurricane import (
- DbU, DataBase, UpdateSession, Box, Transformation, Instance,
- Contact, Vertical, Pad, Pin, NetExternalComponents,
-)
-from helpers import l, showPythonTrace
-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]
+def coriolis_setup():
+ 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
- layer = DataBase.getDB().getTechnology().getLayer(name)
- layer_cache[name] = layer
- return layer
+ env = af.getEnvironment()
+ env.setCLOCK('^clk$|m_clock')
+ env.setPOWER('vdd')
+ env.setGROUND('vss')
-def toDbU(l):
- return DbU.fromLambda(l)
+class AddSub(Module):
+ def build(self):
+ """ Main routine. """
-def placeAndRoute(cell):
- etesian = Etesian.EtesianEngine.create(cell)
- etesian.place()
+ with SessionManager():
+ self.compute_ab()
+ self.create_pins()
- 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()
+ if self.editor:
+ self.editor.setCell(self.cell)
- return success
+ result = self.place_and_route()
+ with SessionManager():
+ self.create_pads()
-def coriolisSetup():
- Cfg.Configuration.pushDefaultPriority(Cfg.Parameter.Priority.UserFile)
+ self.save()
+ return result
- 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(**kwargs):
- editor = kwargs.get('editor', None)
-
- 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))
-
- 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)
-
- for i in range(BIT_WIDTH):
- x = 20.0 * i + 10.0
- y = height
- pin = Pin.create(
- cell.getNet('a(%d)' % i),
- 'a(%d).0' % i,
- Pin.Direction.NORTH,
- Pin.PlacementStatus.FIXED,
- METAL3,
- l(x),
- l(y - 0),
- l(2.0),
- l(2.0),
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
-
- for i in range(BIT_WIDTH):
- pin = Pin.create(
- cell.getNet('o(%d)' % i),
- 'o(%d).0' % i,
- Pin.Direction.SOUTH,
- Pin.PlacementStatus.FIXED,
- METAL3,
- l(10.0 * i + 100.0),
- l(0), # Position.
- l(2.0),
- l(2.0), # Size.
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
-
- for i in range(BIT_WIDTH):
- net = cell.getNet('b(%d)' % i)
- x = 20.0 * i + 10.0 + 10
- y = height - 0
- pin = Pin.create(
- net,
- 'b(%d).0' % i,
- Pin.Direction.NORTH,
- Pin.PlacementStatus.FIXED,
- METAL3,
- l(x),
- l(y - 0), # Position.
- l(2.0),
- l(2.0), # Size.
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
-
- UpdateSession.close()
-
- if editor:
- editor.setCell(cell)
-
- placeAndRoute(cell)
-
- UpdateSession.open()
-
- ab = cell.getAbutmentBox()
- ab.inflate(toDbU(-5.0))
- Pad.create(net, BLOCKAGE2, ab) # do we really want to use net b(15)?
- Pad.create(net, BLOCKAGE3, ab)
- Pad.create(net, BLOCKAGE4, ab)
- UpdateSession.close()
-
- RSavePlugin.ScriptMain(**kwargs)
-
-
-def sub(**kwargs):
- editor = kwargs.get('editor', None)
-
- 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
+class ALU16(Module):
- ab = Box(l(0.0), l(0.0), l(width), l(height))
+ def save(self):
+ self.name = self.name + '_r'
+ self.af.saveCell(self.cell, CRL.Catalog.State.Views)
+ super(ALU16, self).save()
- 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)
-
- for i in range(BIT_WIDTH):
- x = 20.0 * i + 10.0
- y = height
- pin = Pin.create(
- cell.getNet('a(%d)' % i),
- 'a(%d).0' % i,
- Pin.Direction.NORTH,
- Pin.PlacementStatus.FIXED,
- METAL3,
- l(x),
- l(y - 0), # Position.
- l(2.0),
- l(2.0), # Size.
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
-
- for i in range(BIT_WIDTH):
- pin = Pin.create(
- cell.getNet('o(%d)' % i),
- 'o(%d).0' % i,
- Pin.Direction.SOUTH,
- Pin.PlacementStatus.FIXED,
- METAL3,
- l(10.0 * i + 100.0),
- l(0), # Position.
- l(2.0),
- l(2.0), # Size.
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
-
- for i in range(BIT_WIDTH):
- net = cell.getNet('b(%d)' % i)
- x = 20.0 * i + 10.0 + 10
- y = height - 0
- pin = Pin.create(
- net,
- 'b(%d).0' % i,
- Pin.Direction.NORTH,
- Pin.PlacementStatus.FIXED,
- METAL3,
- l(x),
- l(y), # Position.
- l(2.0),
- l(2.0), # Size.
- )
- pin.getNet().setExternal(True)
- NetExternalComponents.setExternal(pin)
+ def build(self):
- UpdateSession.close()
+ h_margin = 25.0
+ v_margin = 10.0
- if editor:
- editor.setCell(cell)
+ if not self.build_submodules():
+ return False
- placeAndRoute(cell)
+ # at this point we have the (auto-calculated) submodules' dimensions
+ # in their `ab` properties.
- UpdateSession.open()
+ add, sub = self.submodules
- ab = cell.getAbutmentBox()
- ab.inflate(toDbU(-5.0))
- Pad.create(net, BLOCKAGE2, ab) # do we really want to use net b(15)?
- Pad.create(net, BLOCKAGE3, ab)
- Pad.create(net, BLOCKAGE4, ab)
- UpdateSession.close()
+ with SessionManager():
+ self.compute_ab()
- RSavePlugin.ScriptMain(**kwargs)
+ 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
+ # experiment, over-ride
+ width = 1300
+ height = 370
-def alu16(**kwargs):
- editor = kwargs.get('editor', None)
+ self.ab = Box(0, 0, self.to_dbu(width), self.to_dbu(height))
- db = DataBase.getDB()
- print(db, dir(db))
- METAL2 = get_layer('METAL2')
- METAL3 = get_layer('METAL3')
+ 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)
- 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
+ # 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
- ab = Box(l(0.0), l(0.0), l(1100.0), l(600.0))
+ self.create_pins()
- UpdateSession.open()
- cell.setAbutmentBox(ab)
+ if self.editor:
+ self.editor.setCell(self.cell)
- # get instances inside cell
- instances = cell.getInstances()
+ # 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
- # find adder instance
- add_inst = [x for x in instances if x.getName().endswith('add')][0]
- add_inst.setTransformation(
- Transformation(
- toDbU(25.0), toDbU(75.0), Transformation.Orientation.ID
+ # 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*
+ self.ab = Box(0, 0, self.to_dbu(width), self.to_dbu(height))
+ result = self.route()
+
+ self.save()
+ 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,
)
- add_inst.setPlacementStatus(Instance.PlacementStatus.FIXED)
-
- # find subtractor instance
- sub_inst = [x for x in instances if x.getName().endswith('sub')][0]
- sub_inst.setTransformation(
- Transformation(
- toDbU(725.0), toDbU(75.0), Transformation.Orientation.ID
- )
+ 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,
)
- sub_inst.setPlacementStatus(Instance.PlacementStatus.FIXED)
-
- yNorth = cell.getAbutmentBox().getYMax()
-
- for i in range(BIT_WIDTH):
- Pin.create(
- cell.getNet('a(%d)' % i),
- 'a(%d).0' % i,
- Pin.Direction.SOUTH,
- Pin.PlacementStatus.FIXED,
- METAL3,
- l(60.0 * i + 50.0),
- l(0.0), # Position.
- l(2.0),
- l(2.0), # Size.
- )
- Pin.create(
- cell.getNet('b(%d)' % i),
- 'b(%d).0' % i,
- Pin.Direction.SOUTH,
- Pin.PlacementStatus.FIXED,
- METAL3,
- l(60.0 * i + 80.0),
- l(0.0), # Position.
- l(2.0),
- l(2.0), # Size.
- )
- Pin.create(
- cell.getNet('o(%d)' % i),
- 'o(%d).0' % i,
- Pin.Direction.NORTH,
- Pin.PlacementStatus.FIXED,
- METAL3,
- l(60.0 * i + 50.0),
- yNorth, # Position.
- l(2.0),
- l(2.0), # Size.
- )
- Pin.create(
- cell.getNet('rst'),
- 'rst.0',
- Pin.Direction.WEST,
- Pin.PlacementStatus.FIXED,
- METAL2,
- l(0.0),
- l(140.0),
- l(2.0),
- l(2.0),
+ 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'},
+ ],
)
- UpdateSession.close()
-
- if editor:
- editor.setCell(cell)
-
- print("editor", editor, dir(editor))
-
- # 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))
-
- cell.setAbutmentBox(ab2)
- etesian = Etesian.EtesianEngine.create(cell)
- etesian.place()
-
- # 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)
-
- result = placeAndRoute(cell)
-
- af.saveCell(cell, CRL.Catalog.State.Views)
- RSavePlugin.ScriptMain(**kwargs)
-
- return result
-
-
-def ScriptMain(**kwargs):
- coriolisSetup()
- add(**kwargs)
- sub(**kwargs)
- return alu16(**kwargs)
+ return alu16.build()
if __name__ == '__main__':