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 Hurricane import Breakpoint
+from Hurricane import Instance
+from coriolis2.settings import af
+from utils import Module, SessionManager, Config
import symbolic.cmos # do not remove
-af = CRL.AllianceFramework.get()
-
-
-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 toDbU(l):
- return DbU.fromLambda(l)
-
-
-def placeAndRoute(cell):
- 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 coriolisSetup():
- 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(**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(16):
- 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(16):
- 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(16):
- 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
-
- 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,
+BIT_WIDTH = 16
+widths = {32: 600.0, 16: 490}
+
+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 = "10.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 build(self):
+ """ Main routine. """
+
+ with SessionManager():
+ #self.compute_ab()
+ self.create_pins()
+
+ if self.editor:
+ self.editor.setCell(self.cell)
+
+ result = self.place_and_route()
+
+ with SessionManager():
+ self.create_pads()
+
+ self.save()
+ return result
+
+
+class ALU16(Module):
+
+ def place_datapath(self, datapath_insts, x_orig, y_orig, fold):
+ channel_sff1 = self.to_dbu(0)
+ with SessionManager():
+ slice_height = self.to_dbu(50.0)
+ for i in range(len(datapath_insts)):
+ if not i%fold:
+ x = self.to_dbu(x_orig)
+ slice = i/fold
+ if slice%2:
+ y = self.to_dbu(y_orig) + slice_height*(slice+1)
+ orient = Transformation.Orientation.MY
+ else:
+ y = self.to_dbu(y_orig) + slice_height*slice
+ orient = Transformation.Orientation.ID
+
+ for (opname, inst) in datapath_insts[i]:
+ if opname == 'sff1':
+ x += channel_sff1
+ inst.setTransformation(Transformation(x, y, orient))
+ inst.setPlacementStatus(Instance.PlacementStatus.PLACED)
+ x += inst.getAbutmentBox().getWidth()
+
+ def place(self):
+ """ALU16.place(), manual placement overload."""
+ datapath_insts = []
+ for i in range(BIT_WIDTH):
+ datapath_insts.append([['nmx2', None],
+ ['no2', None],
+ ['sff1', None]])
+
+ for inst in self.cell.getInstances():
+ if (Module.match_instance(datapath_insts, 'nmx2', 'i0', inst) or
+ Module.match_instance(datapath_insts, 'no2', 'nq', inst) or
+ Module.match_instance(datapath_insts, 'sff1', 'i', inst)):
+ continue
+
+ # place to right of add
+ add, sub = self.submodules
+ add_wid = self.from_dbu(add.ab.getWidth())
+ self.place_datapath(datapath_insts, add_wid, 40.0, 1)
+
+ def save(self):
+ self.name = self.name + '_r'
+ self.af.saveCell(self.cell, CRL.Catalog.State.Views)
+ super(ALU16, self).save()
+
+ def build(self):
+
+ h_margin = 0.0
+ v_margin = 40.0
+
+ if not self.build_submodules():
+ return False
+
+ # at this point we have the (auto-calculated) submodules' dimensions
+ # in their `ab` properties.
+
+ add, sub = self.submodules
+
+ with SessionManager():
+ self.compute_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()
+ ])) + v_margin
+
+ # experiment, over-ride
+ width = widths[BIT_WIDTH]
+ #width = 1310
+ #height = 370
+
+ self.ab = Box(0, 0, self.to_dbu(width), self.to_dbu(height))
+
+ add_wid = self.from_dbu(add.ab.getWidth())
+ sub_ht = self.from_dbu(sub.ab.getHeight())
+ sub_wid = self.from_dbu(sub.ab.getWidth())
+
+ self.place_submodule(add, 0, v_margin)
+ self.place_submodule(sub, width-sub_wid, v_margin)
+
+ # 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
+
+ self.create_pins()
+
+ if False:
+ print (dir(self.cell))
+ for net in self.cell.getNets():
+ print (net.getName())
+ print (self.cell.getNet("a(0)"))
+ print (dir(self.cell.getNet("a(0)")))
+ for inst in self.cell.getInstances():
+ for net in self.cell.getNets():
+ if net.getName() == "a(1)":
+ icell = inst.getMasterCell()
+ #if len(list(icell.getInstances())) > 0:
+ #continue # already placed, do not include it
+ for net in icell.getNets():
+ print ("inst", icell, "has nets", net.getName())
+ sys.exit(0)
+
+ 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
+
+ # 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(475), self.to_dbu(10),
+ # self.to_dbu(840), self.to_dbu(360))
+ self.ab = Box(0, 0, self.to_dbu(width), self.to_dbu(height))
+ 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*
+ result = self.route()
+
+ self.save()
+ return result
+
+
+def scriptMain(editor=None, **kwargs):
+ coriolis_setup()
+
+ add = AddSub(
+ 'add', editor,
+ east_pins=[
+ {'net': 'a({})', 'y': 15.0, 'delta': 50.0,
+ 'repeat': BIT_WIDTH, 'layer': 'METAL2'},
+ {'net': 'b({})', 'y': 20.0, 'delta': 50.0,
+ 'repeat': BIT_WIDTH, 'layer': 'METAL2'},
+ {'net': 'o({})', 'y': 25.0, 'delta': 50.0,
+ 'repeat': BIT_WIDTH, 'layer': 'METAL2'},
+ ],
+ pads={
+ 'b({})'.format(BIT_WIDTH-1): (
+ 'BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4',
+ ),
+ },
+ orientation=Transformation.Orientation.ID,
)
- 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(16):
- 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(16):
- 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(16):
- 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)
-
- 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 alu16(**kwargs):
- editor = kwargs.get('editor', None)
-
- 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
-
- ab = Box(l(0.0), l(0.0), l(1100.0), l(600.0))
-
- UpdateSession.open()
- cell.setAbutmentBox(ab)
-
- ins = cell.getInstance('subckt_48_add')
- ins.setTransformation(
- Transformation(
- toDbU(25.0), toDbU(75.0), Transformation.Orientation.ID
- )
- )
- ins.setPlacementStatus(Instance.PlacementStatus.FIXED)
-
- ins = cell.getInstance('subckt_49_sub')
- ins.setTransformation(
- Transformation(
- toDbU(725.0), toDbU(75.0), Transformation.Orientation.ID
- )
+ add.set_ab(160.0, 50.0 * BIT_WIDTH)
+ sub = AddSub(
+ 'sub', editor,
+ west_pins=[
+ {'net': 'a({})', 'y': 15.0, 'delta': 50.0,
+ 'repeat': BIT_WIDTH, 'layer': 'METAL2'},
+ {'net': 'b({})', 'y': 20.0, 'delta': 50.0,
+ 'repeat': BIT_WIDTH, 'layer': 'METAL2'},
+ {'net': 'o({})', 'y': 25.0, 'delta': 50.0,
+ 'repeat': BIT_WIDTH, 'layer': 'METAL2'},
+ ],
+ pads={
+ 'b({})'.format(BIT_WIDTH-1): (
+ 'BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4',
+ ),
+ },
+ orientation=Transformation.Orientation.ID,
)
- ins.setPlacementStatus(Instance.PlacementStatus.FIXED)
-
- yNorth = cell.getAbutmentBox().getYMax()
-
- for i in range(16):
- 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),
+ sub.set_ab(165.0, 50.0 * BIT_WIDTH)
+
+ o = 00.0
+ alu16 = ALU16(
+ 'alu16', editor, submodules=[add, sub],
+ north_pins=[
+ {'net': 'o({})', 'x': 245.0+o, 'delta': 5.0, 'repeat': BIT_WIDTH},
+ {'net': 'op'},
+ ],
+ south_pins=[
+ {'net': 'a({})', 'x': 195.0+o, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ {'net': 'b({})', 'x': 200.0+o, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ ],
+ east_pins=[
+ {'net': 'rst', 'y': 10.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__':
kwargs = {}
- success = ScriptMain(**kwargs)
+ success = scriptMain(**kwargs)
shellSuccess = 0
if not success:
shellSuccess = 1