from __future__ import print_function
import sys
-import Anabatic
import CRL
import Cfg
-import Etesian
-import Katana
-from Hurricane import (
- DbU, DataBase, UpdateSession, Box, Transformation, Instance, Pin,
- NetExternalComponents,
-)
-from helpers import l
-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
+from utils import Module, SessionManager, Config
import symbolic.cmos # do not remove
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 = 'METAL3'
- if 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
-
+widths = {32: 600.0, 16: 490}
def coriolis_setup():
- Cfg.Configuration.pushDefaultPriority(Cfg.Parameter.Priority.UserFile)
-
- env = af.getEnvironment()
-
- 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(20.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 alu16(editor=None, **kwargs):
-
- db = DataBase.getDB()
- print(db, dir(db))
- METAL2 = get_layer('METAL2')
-
- cell = af.getCell('alu16', CRL.Catalog.State.Logical)
- if not cell:
- print('[ERROR] Unable to load cell "alu16.vst", aborting .')
- return False
-
- width, height = 1100.0, 600.0
- ab = Box(l(0.0), l(0.0), l(width), l(height))
-
- UpdateSession.open()
- cell.setAbutmentBox(ab)
-
- # get instances inside cell
- instances = cell.getInstances()
-
- # 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)
-
- # 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)
-
- 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()
-
- 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 = place_and_route(cell)
-
- cell.setName(cell.getName()+'_r')
- af.saveCell(cell, CRL.Catalog.State.Views)
- RSavePlugin.ScriptMain(editor=editor, cell=cell, **kwargs)
-
- return result
-
-
-def ScriptMain(editor=None, **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 = "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 = 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},
+ 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'},
],
- south_pins=[
- {'net': 'o({})', 'x': 100.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ pads={
+ 'b({})'.format(BIT_WIDTH-1): (
+ 'BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4',
+ ),
+ },
+ orientation=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(15)': ('BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4')},
+ pads={
+ 'b({})'.format(BIT_WIDTH-1): (
+ 'BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4',
+ ),
+ },
+ orientation=Transformation.Orientation.ID,
)
+ sub.set_ab(165.0, 50.0 * BIT_WIDTH)
- sub = Module(
- 'sub', editor, width=350.0, height=400.0,
+ o = 00.0
+ alu16 = ALU16(
+ 'alu16', editor, submodules=[add, sub],
north_pins=[
- {'net': 'a({})', 'x': 10.0, 'delta': 20.0, 'repeat': BIT_WIDTH},
- {'net': 'b({})', 'x': 20.0, 'delta': 20.0, 'repeat': BIT_WIDTH},
+ {'net': 'o({})', 'x': 245.0+o, 'delta': 5.0, 'repeat': BIT_WIDTH},
+ {'net': 'op'},
],
south_pins=[
- {'net': 'o({})', 'x': 100.0, 'delta': 10.0, 'repeat': BIT_WIDTH},
+ {'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'},
],
- pads={'b(15)': ('BLOCKAGE2', 'BLOCKAGE3', 'BLOCKAGE4')},
)
-
- add.do()
- sub.do()
- return alu16(editor, **kwargs)
+ return alu16.build()
if __name__ == '__main__':
kwargs = {}
- success = ScriptMain(**kwargs)
+ success = scriptMain(**kwargs)
shellSuccess = 0
if not success:
shellSuccess = 1