whoops
[soclayout.git] / experiments7 / doAlu16.py
index 749343c88bf81fc840eceb998b454888eb260651..ba1424b4e263d3fec446f89e9f130ccf7ca17d1f 100755 (executable)
 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