Adding Configuration support to Etesian.

* Change: In Bootstrap & ccb, the coloquinte project is renamed into
    "importeds", it will be the home of all the externally
    devellopped softwares that are needed to build Coriolis.
      Add explicit support for Fedora ("Linux.fc") and uses
    site-packages, as everybody else.
* New: In CRL Core, in etc/, adds the configuration files for Etesian.
* New: In Etesian, activate the Configuration object. Now uses it's
    own configuration variables instead of borrowing those of
    Nimbus & Mauka.
* Change: In Documentation, updated User's Guide to present Etesian
    as the placer, instead of Mauka.
* Change: In Cumulus, slight change in ClokTreePlugin and ChipPlugin
    to match the new Etesian/Python interface.
This commit is contained in:
Jean-Paul Chaput 2015-02-27 18:16:03 +01:00
parent bd3984a313
commit 8566126acc
23 changed files with 470 additions and 300 deletions

View File

@ -5,7 +5,7 @@
projectdir = 'coriolis-2.x' projectdir = 'coriolis-2.x'
projects = [ { 'name' : "coloquinte" projects = [ { 'name' : "importeds"
, 'tools' : [ "Coloquinte" ] , 'tools' : [ "Coloquinte" ]
, 'repository': 'https://github.com/alnurn/Coloquinte' } , 'repository': 'https://github.com/alnurn/Coloquinte' }

View File

@ -38,6 +38,8 @@ def guessOs ():
osSlsoc6x = re.compile (".*Linux.*(el|slsoc)6.*") osSlsoc6x = re.compile (".*Linux.*(el|slsoc)6.*")
osSLSoC5x_64 = re.compile (".*Linux.*el5.*x86_64.*") osSLSoC5x_64 = re.compile (".*Linux.*el5.*x86_64.*")
osSLSoC5x = re.compile (".*Linux.*(el5|2.6.23.13.*SoC).*") osSLSoC5x = re.compile (".*Linux.*(el5|2.6.23.13.*SoC).*")
osFedora_64 = re.compile (".*Linux.*fc.*x86_64.*")
osFedora = re.compile (".*Linux.*fc.*")
osLinux_64 = re.compile (".*Linux.*x86_64.*") osLinux_64 = re.compile (".*Linux.*x86_64.*")
osLinux = re.compile (".*Linux.*") osLinux = re.compile (".*Linux.*")
osDarwin = re.compile (".*Darwin.*") osDarwin = re.compile (".*Darwin.*")
@ -70,6 +72,11 @@ def guessOs ():
libDir = "lib64" libDir = "lib64"
elif osSLSoC5x.match(lines[0]): elif osSLSoC5x.match(lines[0]):
osType = "Linux.SLSoC5x" osType = "Linux.SLSoC5x"
elif osFedora_64.match(lines[0]):
osType = "Linux.fc_64"
libDir = "lib64"
elif osFedora.match(lines[0]):
osType = "Linux.fc"
elif osUbuntu1004.match(lines[0]): elif osUbuntu1004.match(lines[0]):
osType = "Linux.Ubuntu1004" osType = "Linux.Ubuntu1004"
elif osUbuntu1004_64.match(lines[0]): elif osUbuntu1004_64.match(lines[0]):
@ -195,6 +202,7 @@ if __name__ == "__main__":
if osType.startswith("Linux.SL") \ if osType.startswith("Linux.SL") \
or osType.startswith("Linux.sl") \ or osType.startswith("Linux.sl") \
or osType.startswith("Linux.el") \ or osType.startswith("Linux.el") \
or osType.startswith("Linux.fc") \
or osType.startswith("Darwin") \ or osType.startswith("Darwin") \
or osType.startswith("Cygwin"): or osType.startswith("Cygwin"):
sitePackagesDir = "%s/python%s/site-packages" % (absLibDir,version) sitePackagesDir = "%s/python%s/site-packages" % (absLibDir,version)

View File

@ -0,0 +1,5 @@
# -*- Mode:Python; explicit-buffer-name: "etesian.conf<cmos>" -*-
import helpers
execfile( helpers.sysConfDir+'/common/etesian.conf' )

View File

@ -0,0 +1,37 @@
# -*- Mode:Python; explicit-buffer-name: "etesian.conf<common>" -*-
# Etesian parameters.
parametersTable = \
( ('etesian.aspectRatio' , TypePercentage, 100 , { 'min':10, 'max':1000 } )
, ('etesian.spaceMargin' , TypePercentage, 5 )
, ('etesian.uniformDensity' , TypeBool , False )
, ('etesian.routingDriven' , TypeBool , False )
, ("etesian.effort" , TypeEnumerate , 2
, { 'values':( ("Fast" , 1)
, ("Standard" , 2)
, ("High" , 3)
, ("Extreme" , 4) ) }
)
, ("etesian.graphics" , TypeEnumerate , 2
, { 'values':( ("Show every step" , 1)
, ("Show lower bound" , 2)
, ("Show result only" , 3) ) }
)
)
layoutTable = \
( (TypeTab , 'Etesian', 'etesian')
, (TypeTitle , 'Placement area')
, (TypeOption, "etesian.aspectRatio" , "Aspect Ratio, X/Y (%)", 0 )
, (TypeOption, "etesian.spaceMargin" , "Space Margin" , 1 )
, (TypeRule ,)
, (TypeTitle , 'Etesian - Placer')
, (TypeOption, "etesian.uniformDensity" , "Uniform density" , 0 )
, (TypeOption, "etesian.routingDriven" , "Routing driven" , 0 )
, (TypeOption, "etesian.effort" , "Placement effort" , 1 )
, (TypeOption, "etesian.graphics" , "Placement view" , 1 )
, (TypeRule ,)
)

View File

@ -0,0 +1,5 @@
# -*- Mode:Python; explicit-buffer-name: "etesian.conf<cmos>" -*-
import helpers
execfile( helpers.sysConfDir+'/common/etesian.conf' )

View File

@ -0,0 +1,5 @@
# -*- Mode:Python; explicit-buffer-name: "etesian.conf<cmos>" -*-
import helpers
execfile( helpers.sysConfDir+'/common/etesian.conf' )

View File

@ -0,0 +1,5 @@
# -*- Mode:Python; explicit-buffer-name: "etesian.conf<cmos>" -*-
import helpers
execfile( helpers.sysConfDir+'/common/etesian.conf' )

View File

@ -116,6 +116,7 @@ def coriolisConfigure():
, (helpers.sysConfDir+'/'+symbolicTechno+'/hMetis.conf' , SystemFile|ConfigurationHelper) , (helpers.sysConfDir+'/'+symbolicTechno+'/hMetis.conf' , SystemFile|ConfigurationHelper)
, (helpers.sysConfDir+'/'+symbolicTechno+'/nimbus.conf' , SystemFile|ConfigurationHelper) , (helpers.sysConfDir+'/'+symbolicTechno+'/nimbus.conf' , SystemFile|ConfigurationHelper)
, (helpers.sysConfDir+'/'+symbolicTechno+'/mauka.conf' , SystemFile|ConfigurationHelper) , (helpers.sysConfDir+'/'+symbolicTechno+'/mauka.conf' , SystemFile|ConfigurationHelper)
, (helpers.sysConfDir+'/'+symbolicTechno+'/etesian.conf' , SystemFile|ConfigurationHelper)
, (helpers.sysConfDir+'/'+symbolicTechno+'/kite.conf' , SystemFile|ConfigurationHelper) , (helpers.sysConfDir+'/'+symbolicTechno+'/kite.conf' , SystemFile|ConfigurationHelper)
, (helpers.sysConfDir+'/'+symbolicTechno+'/stratus1.conf', SystemFile|ConfigurationHelper) , (helpers.sysConfDir+'/'+symbolicTechno+'/stratus1.conf', SystemFile|ConfigurationHelper)
, (helpers.sysConfDir+'/'+symbolicTechno+'/plugins.conf' , SystemFile|ConfigurationHelper) , (helpers.sysConfDir+'/'+symbolicTechno+'/plugins.conf' , SystemFile|ConfigurationHelper)

View File

@ -0,0 +1,27 @@
import Cfg
print " - Loading Mauka configuration."
# Etesian parameters.
Cfg.getParamPercentage("etesian.aspectRatio" ).setPercentage(100 )
Cfg.getParamPercentage("etesian.spaceMargin" ).setPercentage(5 )
Cfg.getParamBool ("etesian.uniformDensity").setBool (False )
Cfg.getParamBool ("etesian.routingDriven").setBool (False )
layout = Cfg.Configuration.get().getLayout()
# Etesian tab layout.
layout.addTab ( "Etesian", "etesian" )
layout.addTitle ( "Etesian", "Placement area" )
layout.addParameter ( "Etesian", "etesian.aspectRatio" , "Aspect Ratio, X/Y (%)", 0 )
layout.addParameter ( "Etesian", "etesian.spaceMargin" , "Space Margin" , 1 )
layout.addRule ( "Etesian" )
layout.addTitle ( "Etesian", "Etesian - Placer" )
layout.addParameter ( "Etesian", "etesian.uniformDensity" , "Occupy whole placement area" , 0 )
layout.addParameter ( "Etesian", "etesian.routingDriven" , "Routing driven" , 0 )
layout.addParameter ( "Etesian", "etesian.effort" , "Placement effort" , 1 )
layout.addParameter ( "Etesian", "etesian.graphics" , "Placement view" , 1 )
layout.addRule ( "Etesian" )

View File

@ -147,7 +147,7 @@ class PlaceCore ( chip.Configuration.ChipConfWrapper ):
mauka.destroy() mauka.destroy()
else: else:
etesian = Etesian.EtesianEngine.create( coreCell ) etesian = Etesian.EtesianEngine.create( coreCell )
etesian.place( Etesian.EtesianEngine.SlowMotion ) etesian.place()
etesian.destroy() etesian.destroy()
ht.connectLeaf() ht.connectLeaf()
@ -161,7 +161,7 @@ class PlaceCore ( chip.Configuration.ChipConfWrapper ):
mauka.destroy() mauka.destroy()
else: else:
etesian = Etesian.EtesianEngine.create( coreCell ) etesian = Etesian.EtesianEngine.create( coreCell )
etesian.place( Etesian.EtesianEngine.SlowMotion ) etesian.place()
etesian.destroy() etesian.destroy()
return return

View File

@ -94,8 +94,8 @@ def ScriptMain ( **kw ):
cellGauge = framework.getCellGauge() cellGauge = framework.getCellGauge()
if cell.getAbutmentBox().isEmpty(): if cell.getAbutmentBox().isEmpty():
spaceMargin = Cfg.getParamPercentage('nimbus.spaceMargin').asPercentage() / 100.0 + 0.02 spaceMargin = Cfg.getParamPercentage('etesian.spaceMargin').asPercentage() / 100.0 + 0.02
aspectRatio = Cfg.getParamPercentage('nimbus.aspectRatio').asPercentage() / 100.0 aspectRatio = Cfg.getParamPercentage('etesian.aspectRatio').asPercentage() / 100.0
clocktree.ClockTree.computeAbutmentBox( cell, spaceMargin, aspectRatio, cellGauge ) clocktree.ClockTree.computeAbutmentBox( cell, spaceMargin, aspectRatio, cellGauge )
if editor: editor.fit() if editor: editor.fit()
@ -109,7 +109,7 @@ def ScriptMain ( **kw ):
mauka.destroy() mauka.destroy()
else: else:
etesian = Etesian.EtesianEngine.create( cell ) etesian = Etesian.EtesianEngine.create( cell )
etesian.place( Etesian.EtesianEngine.SlowMotion ) etesian.place()
etesian.destroy() etesian.destroy()
ht.connectLeaf() ht.connectLeaf()

View File

@ -18,15 +18,27 @@
.. |Flute| replace:: :sc:`Flute` .. |Flute| replace:: :sc:`Flute`
.. |MacOS| replace:: :sc:`MacOS` .. |MacOS| replace:: :sc:`MacOS`
.. |RHEL6| replace:: :sc:`rhel6` .. |RHEL6| replace:: :sc:`rhel6`
.. |RHEL7| replace:: :sc:`rhel7`
.. |SL6| replace:: :sc:`Scientific Linux 6` .. |SL6| replace:: :sc:`Scientific Linux 6`
.. |SL7| replace:: :sc:`Scientific Linux 7`
.. |Scientific Linux| replace:: :sc:`Scientific Linux`
.. |RedHat| replace:: :sc:`RedHat`
.. |Fedora| replace:: :sc:`Fedora`
.. |FC13| replace:: :sc:`fc13`
.. |Debian| replace:: :sc:`Debian`
.. |Ubuntu| replace:: :sc:`Ubuntu`
.. |Alexandre| replace:: :sc:`Alexandre` .. |Alexandre| replace:: :sc:`Alexandre`
.. |Belloeil| replace:: :sc:`Belloeil` .. |Belloeil| replace:: :sc:`Belloeil`
.. |Chaput| replace:: :sc:`Chaput` .. |Chaput| replace:: :sc:`Chaput`
.. |Chu| replace:: :sc:`Chu` .. |Chu| replace:: :sc:`Chu`
.. |Clement| replace:: :sc:`Clement`
.. |Dupuis| replace:: :sc:`Dupuis` .. |Dupuis| replace:: :sc:`Dupuis`
.. |Escassut| replace:: :sc:`Escassut` .. |Escassut| replace:: :sc:`Escassut`
.. |Gouvine| replace:: :sc:`Gouvine`
.. |Masson| replace:: :sc:`Masson` .. |Masson| replace:: :sc:`Masson`
.. |Sroka| replace:: :sc:`Sroka`
.. |Yifei| replace:: :sc:`Yifei`
.. |ANSI| replace:: :sc:`ansi` .. |ANSI| replace:: :sc:`ansi`
.. |MIPS| replace:: :sc:`mips` .. |MIPS| replace:: :sc:`mips`
@ -37,6 +49,7 @@
.. |GenLib| replace:: :sc:`GenLib` .. |GenLib| replace:: :sc:`GenLib`
.. |Nero| replace:: :sc:`Nero` .. |Nero| replace:: :sc:`Nero`
.. |Druc| replace:: :cb:`Druc` .. |Druc| replace:: :cb:`Druc`
.. |Coloquinte| replace:: :sc:`Coloquinte`
.. |Coriolis| replace:: :sc:`Coriolis` .. |Coriolis| replace:: :sc:`Coriolis`
.. |Coriolis1| replace:: :sc:`Coriolis 1` .. |Coriolis1| replace:: :sc:`Coriolis 1`
.. |Coriolis2| replace:: :sc:`Coriolis 2` .. |Coriolis2| replace:: :sc:`Coriolis 2`
@ -46,6 +59,7 @@
.. |Nimbus| replace:: :sc:`Nimbus` .. |Nimbus| replace:: :sc:`Nimbus`
.. |hMetis| replace:: :sc:`hMetis` .. |hMetis| replace:: :sc:`hMetis`
.. |Mauka| replace:: :sc:`Mauka` .. |Mauka| replace:: :sc:`Mauka`
.. |Etesian| replace:: :sc:`Etesian`
.. |Knik| replace:: :sc:`Knik` .. |Knik| replace:: :sc:`Knik`
.. |Katabatic| replace:: :sc:`Katabatic` .. |Katabatic| replace:: :sc:`Katabatic`
.. |Kite| replace:: :sc:`Kite` .. |Kite| replace:: :sc:`Kite`
@ -65,12 +79,6 @@
.. |UTF-8| replace:: :sc:`utf-8` .. |UTF-8| replace:: :sc:`utf-8`
.. |Python| replace:: :sc:`Python` .. |Python| replace:: :sc:`Python`
.. |Linux| replace:: :sc:`Linux` .. |Linux| replace:: :sc:`Linux`
.. |Scientific Linux| replace:: :sc:`Scientific Linux`
.. |RedHat| replace:: :sc:`RedHat`
.. |Fedora| replace:: :sc:`Fedora`
.. |FC13| replace:: :sc:`fc13`
.. |Debian| replace:: :sc:`Debian`
.. |Ubuntu| replace:: :sc:`Ubuntu`
.. |MacPorts| replace:: :sc:`MacPorts` .. |MacPorts| replace:: :sc:`MacPorts`
.. |devtoolset2| replace:: :cb:`devtoolset2` .. |devtoolset2| replace:: :cb:`devtoolset2`
.. |boost| replace:: :cb:`boost` .. |boost| replace:: :cb:`boost`
@ -79,6 +87,9 @@
.. |svn| replace:: :cb:`svn` .. |svn| replace:: :cb:`svn`
.. |git| replace:: :cb:`git` .. |git| replace:: :cb:`git`
.. |rpm| replace:: :cb:`rpm` .. |rpm| replace:: :cb:`rpm`
.. |gdb| replace:: :cb:`gdb`
.. |CTRL_L| replace:: :fboxtt:`CTRL+L`
.. URLs .. URLs
.. _FGR: http://vlsicad.eecs.umich.edu/BK/FGR/ .. _FGR: http://vlsicad.eecs.umich.edu/BK/FGR/
@ -154,8 +165,8 @@ Credits & License
<span class="right">Rémy <span class="sc">Escassut</span> &amp; <span class="right">Rémy <span class="sc">Escassut</span> &amp;
Christian <span class="sc">Masson</span></span></p> Christian <span class="sc">Masson</span></span></p>
<br> <br>
<p class="credit"><span class="left"><span class="sc">Mauka</span></span> <p class="credit"><span class="left"><span class="sc">Etesian</span></span>
<span class="right">Christophe <span class="sc">Alexandre</span></span></p> <span class="right">Gabriel <span class="sc">Gouvine</span></span></p>
<br> <br>
<p class="credit"><span class="left"><span class="sc">Stratus</span></span> <p class="credit"><span class="left"><span class="sc">Stratus</span></span>
<span class="right">Sophie <span class="sc">Belloeil</span></span></p> <span class="right">Sophie <span class="sc">Belloeil</span></span></p>
@ -174,7 +185,7 @@ Credits & License
\begin{center}\begin{minipage}[t]{.8\textwidth} \begin{center}\begin{minipage}[t]{.8\textwidth}
\noindent\DUrole{sc}{Hurricane} \dotfill Rémy \DUrole{sc}{Escassut} \& \noindent\DUrole{sc}{Hurricane} \dotfill Rémy \DUrole{sc}{Escassut} \&
Christian \DUrole{Masson} \\ Christian \DUrole{Masson} \\
\noindent\DUrole{sc}{Mauka} \dotfill Christophe \DUrole{sc}{Alexandre} \\ \noindent\DUrole{sc}{Etesian} \dotfill Gabriel \DUrole{sc}{Gouvine} \\
\noindent\DUrole{sc}{Stratus} \dotfill Sophie \DUrole{sc}{Belloeil} \\ \noindent\DUrole{sc}{Stratus} \dotfill Sophie \DUrole{sc}{Belloeil} \\
\noindent\DUrole{sc}{Knik} \dotfill Damien \DUrole{sc}{Dupuis} \\ \noindent\DUrole{sc}{Knik} \dotfill Damien \DUrole{sc}{Dupuis} \\
\noindent\DUrole{sc}{Kite}, \noindent\DUrole{sc}{Kite},
@ -184,11 +195,14 @@ Credits & License
|medskip| |medskip|
The |Hurricane| data-base is copyright© |Bull| 2000-2014 and is The |Hurricane| data-base is copyright© |Bull| 2000-2015 and is
released under the terms of the |LGPL| license. All other tools are released under the terms of the |LGPL| license. All other tools are
copyright© |UPMC| 2008-2014 and released under the |GPL| copyright© |UPMC| 2008-2015 and released under the |GPL|
license. license.
Others important contributors to |Coriolis| are Christophe |Alexandre|,
Hugo |Clement|, Marek |Sroka| and Wu |Yifei|.
The |Knik| router makes use of the |Flute| software, which is The |Knik| router makes use of the |Flute| software, which is
copyright© Chris C. N. |Chu| from the Iowa State University copyright© Chris C. N. |Chu| from the Iowa State University
(http://home.eng.iastate.edu/~cnchu/). (http://home.eng.iastate.edu/~cnchu/).
@ -270,6 +284,21 @@ Release **v2.0.1**
achieve a speedup factor greater than 20... achieve a speedup factor greater than 20...
Release **v3.0**
~~~~~~~~~~~~~~~~
#. Replace the old simulated annealing placer |Mauka| by an analytic placer
|Etesian|.
#. The multiples user defined configuration files are now grouped under
a common hidden (dot) directory ``.coriolis2`` and the file extension
is back from ``.conf`` to ``.py``.
#. Under |RHEL7| / |SL7|, there is a known bug in the graphical visualizer.
When shifting to the left, the right-half part of the screen gets
badly redrawn. Uses |CTRL_L| to refresh. It will be corrected as soon
as possible.
|newpage| |newpage|
@ -290,9 +319,8 @@ Main building prerequisites:
* boost * boost
* libxml2 * libxml2
* yacc & lex. * yacc & lex.
* Qt 4 * Qt 4 or Qt 5.
* LEF/DEF (optional). * LEF/DEF (optional).
* hMetis (optional).
* doxygen. * doxygen.
* latex * latex
* latex2html. * latex2html.
@ -314,11 +342,15 @@ automatically created either by |ccb| or the build system.
+--------------------------+-----------------------------------------------------------------------------+ +--------------------------+-----------------------------------------------------------------------------+
| | Sources root | | ~/coriolis-2.x/src | | | Sources root | | ~/coriolis-2.x/src |
| | **under git** | | ~/coriolis-2.x/src/coriolis | | | **under git** | | ~/coriolis-2.x/src/coriolis |
| | **under git** | | ~/coriolis-2.x/src/importeds/Coloquinte |
+--------------------------+-----------------------------------------------------------------------------+ +--------------------------+-----------------------------------------------------------------------------+
| **Architecture Dependant Build** | | **Architecture Dependant Build** |
+--------------------------+-----------------------------------------------------------------------------+ +--------------------------+-----------------------------------------------------------------------------+
| | Linux, SL 7, 64 bits | | ~/coriolis-2.x/Linux.el7_64/Release.Shared/build/<tool> |
| | Linux, SL 6, 32 bits | | ~/coriolis-2.x/Linux.slsoc6x/Release.Shared/build/<tool> | | | Linux, SL 6, 32 bits | | ~/coriolis-2.x/Linux.slsoc6x/Release.Shared/build/<tool> |
| | Linux, SL 6, 64 bits | | ~/coriolis-2.x/Linux.slsoc6x_64/Release.Shared/build/<tool> | | | Linux, SL 6, 64 bits | | ~/coriolis-2.x/Linux.slsoc6x_64/Release.Shared/build/<tool> |
| | Linux, Fedora, 64 bits | | ~/coriolis-2.x/Linux.fc_64/Release.Shared/build/<tool> |
| | Linux, Fedora, 32 bits | | ~/coriolis-2.x/Linux.fc/Release.Shared/build/<tool> |
| | FreeBSD 8, 32 bits | | ~/coriolis-2.x/FreeBSD.8x.i386/Release.Shared/build/<tool> | | | FreeBSD 8, 32 bits | | ~/coriolis-2.x/FreeBSD.8x.i386/Release.Shared/build/<tool> |
| | FreeBSD 8, 64 bits | | ~/coriolis-2.x/FreeBSD.8x.amd64/Release.Shared/build/<tool> | | | FreeBSD 8, 64 bits | | ~/coriolis-2.x/FreeBSD.8x.amd64/Release.Shared/build/<tool> |
| | Windows 7, 32 bits | | ~/coriolis-2.x/Cygwin.W7/Release.Shared/build/<tool> | | | Windows 7, 32 bits | | ~/coriolis-2.x/Cygwin.W7/Release.Shared/build/<tool> |
@ -355,17 +387,28 @@ The first step is to create the source directory and pull the |git| repository:
dummy@lepka:~$ mkdir -p ~/coriolis-2.x/src dummy@lepka:~$ mkdir -p ~/coriolis-2.x/src
dummy@lepka:~$ cd ~/coriolis-2.x/src dummy@lepka:~$ cd ~/coriolis-2.x/src
dummy@lepka:~$ git clone https://www-soc.lip6.fr/git/coriolis.git dummy@lepka:~$ git clone https://www-soc.lip6.fr/git/coriolis.git
dummy@lepka:~$ cd coriolis dummy@lepka:~$ mkdir importeds
dummy@lepka:~$ cd importeds
dummy@lepka:~$ git clone https://github.com/Coloquinte/Coloquinte.git
dummy@lepka:~$ cd ../coriolis
Second and final step, build & install: :: Second and final step, build & install: ::
dummy@lepka:src$ ./bootstrap/ccp.py --project=coriolis --make="-j4 install" dummy@lepka:src$ ./bootstrap/ccp.py --project=importeds --project=coriolis \
--make="-j4 install"
dummy@lepka:src$ ./bootstrap/ccb.py --project=coriolis --doc --make="-j1 install" dummy@lepka:src$ ./bootstrap/ccb.py --project=coriolis --doc --make="-j1 install"
We need two steps because the documentation do not support to be generated with We need two steps because the documentation do not support to be generated with
a parallel build. So we compile & install in a first step in ``-j4`` (or whatever) a parallel build. So we compile & install in a first step in ``-j4`` (or whatever)
then we generate the documentation in ``-j1`` then we generate the documentation in ``-j1``
Under |RHEL6| or clones, you must build using the |devtoolset2|: ::
dummy@lepka:src$ ./bootstrap/ccp.py --project=importeds --project=coriolis \
--devtoolset-2 --make="-j4 install"
If you want to uses Qt 5 instead of Qt 4, you may add the ``--qt5`` argument.
The complete list of |ccb| functionalities can be accessed with the ``--help`` argument. The complete list of |ccb| functionalities can be accessed with the ``--help`` argument.
It also may be run in graphical mode (``--gui``). It also may be run in graphical mode (``--gui``).
@ -383,13 +426,16 @@ In the |Coriolis| |git| repository, two branches are present:
command just after the first step: :: command just after the first step: ::
dummy@lepka:~$ git checkout devel dummy@lepka:~$ git checkout devel
dummy@lepka:src$ ./bootstrap/ccp.py --project=importeds --project=coriolis \
--make="-j4 install" --debug
Be aware that it may requires newer versions of the dependencies and may introduce Be aware that it may requires newer versions of the dependencies and may introduce
incompatibilites with the stable version. incompatibilites with the stable version.
Under |RHEL6| or clones, you must build using the |devtoolset2|: :: In the (unlikely) event of a crash of |cgt|, as it is a |Python| script, the right
command to run |gdb| on it is: ::
dummy@lepka:src$ ./bootstrap/ccp.py --project=coriolis --devtoolset-2 --make="-j4 install" dummy@lepka:work$ gdb python core.XXXX
Additionnal Requirement under |MacOS| Additionnal Requirement under |MacOS|
@ -513,11 +559,11 @@ file(s):
+-------+----------------------------------+----------------------------------------------+ +-------+----------------------------------+----------------------------------------------+
| Order | Meaning | File | | Order | Meaning | File |
+=======+==================================+==============================================+ +=======+==================================+==============================================+
| **1** | The system setting | :cb:`/etc/coriolis2/coriolis2_techno.conf` | | **1** | The system setting | :cb:`/etc/coriolis2/techno.conf` |
+-------+----------------------------------+----------------------------------------------+ +-------+----------------------------------+----------------------------------------------+
| **2** | The user's global setting | :cb:`${HOME}/.coriolis2_techno.conf` | | **2** | The user's global setting | :cb:`${HOME}/.coriolis2/techno.py` |
+-------+----------------------------------+----------------------------------------------+ +-------+----------------------------------+----------------------------------------------+
| **3** | The user's local setting | :cb:`<CWD>/.coriolis2_techno.conf` | | **3** | The user's local setting | :cb:`<CWD>/.coriolis2/techno.py` |
+-------+----------------------------------+----------------------------------------------+ +-------+----------------------------------+----------------------------------------------+
Thoses files must provides only two variables, the name of the symbolic technology Thoses files must provides only two variables, the name of the symbolic technology
@ -545,13 +591,13 @@ by executing, in order, the following file(s):
+=======+==================================+==============================================+ +=======+==================================+==============================================+
| **1** | The system initialization | :cb:`/etc/coriolis2/<TECHNO>/<TOOL>.conf` | | **1** | The system initialization | :cb:`/etc/coriolis2/<TECHNO>/<TOOL>.conf` |
+-------+----------------------------------+----------------------------------------------+ +-------+----------------------------------+----------------------------------------------+
| **2** | The user's global initialization | :cb:`${HOME}/.coriolis2.conf` | | **2** | The user's global initialization | :cb:`${HOME}/.coriolis2/settings.py` |
+-------+----------------------------------+----------------------------------------------+ +-------+----------------------------------+----------------------------------------------+
| **3** | The user's local initialization | :cb:`<CWD>/.coriolis2.conf` | | **3** | The user's local initialization | :cb:`<CWD>/.coriolis2/settings.py` |
+-------+----------------------------------+----------------------------------------------+ +-------+----------------------------------+----------------------------------------------+
.. note:: *The loading policy is not hard-coded.* It is implemented .. note:: *The loading policy is not hard-coded.* It is implemented
at Python level in :cb:`/etc/coriolis2/coriolisInit.py`, and thus may be easyly be at Python level in :cb:`/etc/coriolis2/coriolisInit.py`, and thus may be easily be
amended to whatever site policy. amended to whatever site policy.
The truly mandatory requirement is the existence of :cb:`coriolisInit.py` The truly mandatory requirement is the existence of :cb:`coriolisInit.py`
@ -638,22 +684,22 @@ available settings. Some important remarks about thoses settings:
directory in which the system-wide configuration files are locateds. directory in which the system-wide configuration files are locateds.
For a standard installation it would be: ``/soc/coriolis2``. For a standard installation it would be: ``/soc/coriolis2``.
* Trick and naming convention about ``SYMBOLIC_TECHNOLOGY``, ``REAL_TECHNOLOGY`` .. * Trick and naming convention about ``SYMBOLIC_TECHNOLOGY``, ``REAL_TECHNOLOGY``
and ``DISPLAY``. In the previous releases, thoses files where to read by .. and ``DISPLAY``. In the previous releases, thoses files where to read by
|XML| parsers, and still do if you triggers the |XML| compatibility mode. .. XML parsers, and still do if you triggers the XML compatibility mode.
But now, they have Python conterparts. In the configuration files, you .. But now, they have Python conterparts. In the configuration files, you
still have to name them as |XML| files, the Python file name will be .. still have to name them as XML files, the Python file name will be
deduced from this one with thoses two translation rules: .. deduced from this one with thoses two translation rules:
..
#. In the filename, all dots, except for the last (the file extention), .. #. In the filename, all dots, except for the last (the file extention),
are replaced by underscores. .. are replaced by underscores.
..
#. The ``.xml`` extention is substituted by a ``.conf``. .. #. The ``.xml`` extention is substituted by a ``.conf``.
..
For the symbolic technology, it would give: :: .. For the symbolic technology, it would give: ::
..
/soc/coriolis2/technology.symbolic.xml .. /soc/coriolis2/technology.symbolic.xml
--> /soc/coriolis2/technology_symbolic.conf .. --> /soc/coriolis2/technology_symbolic.conf
A typical user's configuration file would be: :: A typical user's configuration file would be: ::
@ -677,37 +723,43 @@ All the tools uses the same helper to load their configuration (a.k.a.
configuration files are defined: configuration files are defined:
* :cb:`misc.conf`: commons settings or not belonging specifically to a tool. * :cb:`misc.conf`: commons settings or not belonging specifically to a tool.
* :cb:`nimbus.conf`: for the |Nimbus| tool. * :cb:`etesian.conf`: for the |Etesian| tool.
* :cb:`hMetis.conf`: for the |hMetis| wrapper.
* :cb:`mauka.conf`: for the |Mauka| tool.
* :cb:`kite.conf`: for the |Kite| tool. * :cb:`kite.conf`: for the |Kite| tool.
* :cb:`stratus1.conf`: for the |stratus1| tool. * :cb:`stratus1.conf`: for the |stratus1| tool.
Here is the contents of :cb:`mauka.conf`: :: Here is the contents of :cb:`etesian.conf`: ::
# Mauka parameters. # Etesian parameters.
parametersTable = \ parametersTable = \
( ('mauka.annealingBinMult' , TypePercentage, 5 ) ( ('etesian.aspectRatio' , TypePercentage, 100 , { 'min':10, 'max':1000 } )
, ('mauka.annealingNetMult' , TypePercentage, 90 ) , ('etesian.spaceMargin' , TypePercentage, 5 )
, ('mauka.annealingRowMult' , TypePercentage, 5 ) , ('etesian.uniformDensity' , TypeBool , False )
, ('mauka.ignorePins' , TypeBool , False ) , ('etesian.routingDriven' , TypeBool , False )
, ('mauka.insertFeeds' , TypeBool , True ) , ("etesian.effort" , TypeEnumerate , 2
, ('mauka.plotBins' , TypeBool , True ) , { 'values':( ("Fast" , 1)
, ('mauka.searchRatio' , TypePercentage, 50 ) , ("Standard", 2)
, ('mauka.standardAnnealing', TypeBool , False ) , ("High" , 3)
, ("Extreme" , 4) ) }
)
, ("etesian.graphics" , TypeEnumerate , 2
, { 'values':( ("Show every step" , 1)
, ("Show lower bound" , 2)
, ("Show result only" , 3) ) }
)
) )
layoutTable = \ layoutTable = \
( (TypeTab , 'Mauka', 'mauka') ( (TypeTab , 'Etesian', 'etesian')
# Mauka part.
, (TypeOption, "mauka.standardAnnealing", "Standart Annealing" , 0 ) , (TypeTitle , 'Placement area')
, (TypeOption, "mauka.ignorePins" , "Ignore Pins" , 0 ) , (TypeOption, "etesian.aspectRatio" , "Aspect Ratio, X/Y (%)", 0 )
, (TypeOption, "mauka.plotBins" , "Plot Bins" , 0 ) , (TypeOption, "etesian.spaceMargin" , "Space Margin" , 1 )
, (TypeOption, "mauka.insertFeeds" , "Insert Feeds" , 0 ) , (TypeRule ,)
, (TypeOption, "mauka.searchRatio" , "Search Ratio (%)" , 1 ) , (TypeTitle , 'Etesian - Placer')
, (TypeOption, "mauka.annealingNetMult" , "Annealing Net Mult (%)", 1 ) , (TypeOption, "etesian.uniformDensity", "Uniform density" , 0 )
, (TypeOption, "mauka.annealingBinMult" , "Annealing Bin Mult (%)", 1 ) , (TypeOption, "etesian.routingDriven" , "Routing driven" , 0 )
, (TypeOption, "mauka.annealingRowMult" , "Annealing Row Mult (%)", 1 ) , (TypeOption, "etesian.effort" , "Placement effort" , 1 )
, (TypeOption, "etesian.graphics" , "Placement view" , 1 )
, (TypeRule ,) , (TypeRule ,)
) )
@ -746,7 +798,7 @@ Hacking the Configuration Files
Asides from the symbols that gets used by the configuration helpers like Asides from the symbols that gets used by the configuration helpers like
:cb:`allianceConfig` or :cb:`parametersTable`, you can put pretty much anything :cb:`allianceConfig` or :cb:`parametersTable`, you can put pretty much anything
in :cb:`<CWD>/.coriolis2.conf` (that is, written in |Python|). in :cb:`<CWD>/.coriolis2/settings.py` (that is, written in |Python|).
For example: :: For example: ::
@ -853,15 +905,12 @@ As for the first release, |Coriolis| can be used only for two purposes :
state. state.
Mauka -- Placer Etesian -- Placer
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
|Mauka| was originally designed to be a recursive quadri-partionner. Unfortunatly The |Etesian| placer is a state of the art (as of 2015) analytical placer. This |Coriolis|
it is was based on the hMETIS_ library (*not* :sc:`METIS`) which is no longer tool is really an encapsulation of |Coloquinte| which *is* the placer. |Coloquinte|
maintained (only an old binary 32 bits version is available). is provided a separate library, see the building instructions.
So now it is only working in simulated annealing, with performances identical to
the |Alliance| placer :cb:`ocp`. In other words, it is slow...
.. note:: *Instance Duplication Problem:* a same logical instance cannot have .. note:: *Instance Duplication Problem:* a same logical instance cannot have
two different placements. So, either you manually make a clone of it or you two different placements. So, either you manually make a clone of it or you
@ -1485,19 +1534,49 @@ Small example of Python/Stratus script: ::
# ... # ...
return return
def ScriptMain ( editor=None ): def ScriptMain ( **kw ):
if globals().has_key( "__editor" ): editor = __editor editor = None
if editor: setEditor( editor ) if kw.has_key('editor') and kw['editor']:
editor = kw['editor']
stratus.setEditor( editor )
doSomething() doSomething()
return return
if __name__ == "__main__" : if __name__ == "__main__" :
kw = {}
success = ScriptMain( **kw )
shellSuccess = 0
if not success: shellSuccess = 1
sys.exit( shellSuccess )
ScriptMain () ScriptMain ()
This script could be run directly with Python (thanks to the two last lines) This typical script can be executed in two ways:
or through |cgt| in both text and graphical modes through the :cb:`ScriptMain()`
function. #. Run directly as a |Python| script, thanks to the ::
if __name__ == "__main__" :
part (this is standart |Python|). It is a simple adapter that will
calls :cb:`ScriptMain()`.
#. Through |cgt|, either in text or graphical mode. In that case, the
:cb:`ScriptMain()` is directly called trough a sub-interpreter.
The arguments of the script are passed through the ``**kw`` dictionnary.
+----------------------+-----------------------------------------------+
| \*\*kw Dictionnary |
+----------------------+-----------------------------------------------+
| Parameter Key/Name | Contents type |
+======================+===============================================+
| ``'cell'`` | A Hurricane cell on which to work. Depending |
| | on the context, it may be ``None``. |
| | For example, when run from |cgt|, it the cell |
| | currently loaded in the viewer, if any. |
+----------------------+-----------------------------------------------+
| ``'editor'`` | The viewer from which the script is run, when |
| | lauched through |cgt|. |
+----------------------+-----------------------------------------------+
A Simple Example: AM2901 A Simple Example: AM2901

View File

@ -11,7 +11,7 @@
find_package(Coloquinte REQUIRED) find_package(Coloquinte REQUIRED)
find_package(Bootstrap REQUIRED) find_package(Bootstrap REQUIRED)
setup_project_paths(CORIOLIS) setup_project_paths(CORIOLIS)
setup_project_paths(COLOQUINTE) setup_project_paths(IMPORTEDS)
setup_qt() setup_qt()
set_cmake_policies() set_cmake_policies()

View File

@ -306,7 +306,7 @@ namespace Etesian {
size_t EtesianEngine::findYSpin () size_t EtesianEngine::findYSpin ()
{ {
_flags &= ~YSpinSet; _ySpinSet = false;
_yspinSlice0 = 0; _yspinSlice0 = 0;
Box topCellAb = getCell()->getAbutmentBox(); Box topCellAb = getCell()->getAbutmentBox();
@ -324,7 +324,7 @@ namespace Etesian {
if (not topCellAb.contains(instanceAb)) continue; if (not topCellAb.contains(instanceAb)) continue;
_flags |= YSpinSet; _ySpinSet = true;
int islice = (instanceAb.getYMin() - getCell()->getAbutmentBox().getYMin()) / getSliceHeight(); int islice = (instanceAb.getYMin() - getCell()->getAbutmentBox().getYMin()) / getSliceHeight();
@ -345,11 +345,11 @@ namespace Etesian {
, getString(instance->getName()).c_str() , getString(instance->getName()).c_str()
, getString(instanceTransf.getOrientation()).c_str() , getString(instanceTransf.getOrientation()).c_str()
) << endl; ) << endl;
_flags &= ~YSpinSet; _ySpinSet = false;
break; break;
} }
if (_flags & YSpinSet) break; if (_ySpinSet) break;
} }
} }

View File

@ -52,19 +52,13 @@ namespace Etesian {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Class : "Etesian::Configuration". // Class : "Etesian::Configuration".
Configuration::Configuration ( const CellGauge* cg )
Configuration::Configuration () { } : _cg ( NULL )
Configuration::~Configuration () { } , _placeEffort ( static_cast<Effort> (Cfg::getParamEnumerate ("etesian.effort" , Standard )->asInt()) )
, _updateConf ( static_cast<GraphicUpdate> (Cfg::getParamEnumerate ("etesian.graphics" , LowerBound )->asInt()) )
, _spreadingConf( Cfg::getParamBool ("etesian.uniformDensity", false )->asBool()?ForceUniform:MaxDensity )
// ------------------------------------------------------------------- , _spaceMargin ( Cfg::getParamPercentage("etesian.spaceMargin" , 5.0)->asDouble() )
// Class : "Etesian::ConfigurationConcrete". , _aspectRatio ( Cfg::getParamPercentage("etesian.aspectRatio" ,100.0)->asDouble() )
ConfigurationConcrete::ConfigurationConcrete ( const CellGauge* cg )
: Configuration()
, _cg (NULL)
, _flags (0)
{ {
if ( cg == NULL ) cg = AllianceFramework::get()->getCellGauge(); if ( cg == NULL ) cg = AllianceFramework::get()->getCellGauge();
@ -72,41 +66,45 @@ namespace Etesian {
} }
ConfigurationConcrete::ConfigurationConcrete ( const ConfigurationConcrete& other ) Configuration::Configuration ( const Configuration& other )
: Configuration() : _cg (NULL)
, _cg (NULL) , _placeEffort ( other._placeEffort )
, _flags (other._flags) , _updateConf ( other._updateConf )
, _spreadingConf( other._spreadingConf )
, _spaceMargin ( other._spaceMargin )
, _aspectRatio ( other._aspectRatio )
{ {
if ( other._cg ) _cg = other._cg->getClone(); if ( other._cg ) _cg = other._cg->getClone();
} }
ConfigurationConcrete::~ConfigurationConcrete () Configuration::~Configuration ()
{ {
ltrace(89) << "About to delete attribute _cg (CellGauge)." << endl; ltrace(89) << "About to delete attribute _cg (CellGauge)." << endl;
_cg->destroy (); _cg->destroy ();
} }
ConfigurationConcrete* ConfigurationConcrete::clone () const { return new ConfigurationConcrete(*this); } Configuration* Configuration::clone () const { return new Configuration(*this); }
CellGauge* ConfigurationConcrete::getCellGauge () const { return _cg; }
bool ConfigurationConcrete::isSlowMotion () const { return _flags & EtesianEngine::SlowMotion; }
void ConfigurationConcrete::setFlags ( unsigned int flags ) { _flags |= flags; }
void ConfigurationConcrete::unsetFlags ( unsigned int flags ) { _flags &= ~flags; }
void ConfigurationConcrete::print ( Cell* cell ) const void Configuration::print ( Cell* cell ) const
{ {
cout << " o Configuration of ToolEngine<Etesian> for Cell <" << cell->getName() << ">" << endl; cout << " o Configuration of ToolEngine<Etesian> for Cell <" << cell->getName() << ">" << endl;
cout << Dots::asIdentifier(" - Cell Gauge" ,getString(_cg->getName())) << endl; cout << Dots::asIdentifier(" - Cell Gauge" ,getString(_cg->getName())) << endl;
cout << Dots::asInt (" - Place Effort" ,_placeEffort ) << endl;
cout << Dots::asInt (" - Update Conf" ,_updateConf ) << endl;
cout << Dots::asInt (" - Spreading Conf",_spreadingConf) << endl;
cout << Dots::asPercentage(" - Space Margin" ,_spaceMargin ) << endl;
cout << Dots::asPercentage(" - Aspect Ratio" ,_aspectRatio ) << endl;
} }
string ConfigurationConcrete::_getTypeName () const string Configuration::_getTypeName () const
{ return "ConfigurationConcrete"; } { return "Configuration"; }
string ConfigurationConcrete::_getString () const string Configuration::_getString () const
{ {
ostringstream os; ostringstream os;
@ -116,12 +114,16 @@ namespace Etesian {
} }
Record* ConfigurationConcrete::_getRecord () const Record* Configuration::_getRecord () const
{ {
Record* record = new Record ( _getString() ); Record* record = new Record ( _getString() );
record->add ( getSlot( "_cg" , _cg ) ); record->add ( getSlot( "_cg" , _cg ) );
record->add ( getSlot( "_placeEffort" , (int)_placeEffort ) );
return ( record ); record->add ( getSlot( "_updateConf" , (int)_updateConf ) );
record->add ( getSlot( "_spreadingConf" , (int)_spreadingConf ) );
record->add ( getSlot( "_spaceMargin" , _spaceMargin ) );
record->add ( getSlot( "_aspectRatio" , _aspectRatio ) );
return record;
} }

View File

@ -267,8 +267,9 @@ namespace Etesian {
EtesianEngine::EtesianEngine ( Cell* cell ) EtesianEngine::EtesianEngine ( Cell* cell )
: ToolEngine (cell) : ToolEngine (cell)
, _configuration(new ConfigurationConcrete()) , _configuration(new Configuration())
, _flags (0) , _placed (false)
, _flatDesign (false)
, _timer () , _timer ()
, _surface () , _surface ()
, _circuit () , _circuit ()
@ -365,8 +366,8 @@ namespace Etesian {
void EtesianEngine::setDefaultAb () void EtesianEngine::setDefaultAb ()
{ {
double spaceMargin = Cfg::getParamPercentage("nimbus.spaceMargin", 10.0)->asDouble(); double spaceMargin = getSpaceMargin();
double aspectRatio = Cfg::getParamPercentage("nimbus.aspectRatio",100.0)->asDouble(); double aspectRatio = getAspectRatio();
size_t instanceNb = 0; size_t instanceNb = 0;
double cellLength = 0; double cellLength = 0;
@ -390,13 +391,8 @@ namespace Etesian {
} }
double gcellLength = cellLength*(1.0+spaceMargin) / DbU::toLambda( getSliceHeight() ); double gcellLength = cellLength*(1.0+spaceMargin) / DbU::toLambda( getSliceHeight() );
double rows = sqrt( gcellLength/aspectRatio ); double rows = std::ceil( sqrt( gcellLength/aspectRatio ) );
if (floor(rows) != rows) rows = floor(rows)+1.0; double columns = std::ceil( gcellLength / rows );
else rows = floor(rows);
double columns = gcellLength / rows;
if (floor(columns) != columns) columns = floor(columns)+1.0;
else columns = floor(columns);
cmess1 << " o Creating abutment box (margin:" << (spaceMargin*100.0) cmess1 << " o Creating abutment box (margin:" << (spaceMargin*100.0)
<< "% aspect ratio:" << (aspectRatio*100.0) << "% aspect ratio:" << (aspectRatio*100.0)
@ -423,8 +419,8 @@ namespace Etesian {
{ {
//cerr << "EtesianEngine::resetPlacement()" << endl; //cerr << "EtesianEngine::resetPlacement()" << endl;
if (_flags & NoPlacement) return; if (not _placed) return;
_flags |= FlatDesign; _flatDesign = true;
Dots dots ( cmess2, " ", 80, 1000 ); Dots dots ( cmess2, " ", 80, 1000 );
@ -436,8 +432,8 @@ namespace Etesian {
{ {
dots.dot(); dots.dot();
if ((_flags & FlatDesign) and not (*ioccurrence).getPath().getTailPath().isEmpty()) if ( _flatDesign and not (*ioccurrence).getPath().getTailPath().isEmpty())
_flags &= ~FlatDesign; _flatDesign = true;
Instance* instance = static_cast<Instance*>((*ioccurrence).getEntity()); Instance* instance = static_cast<Instance*>((*ioccurrence).getEntity());
Cell* masterCell = instance->getMasterCell(); Cell* masterCell = instance->getMasterCell();
@ -459,7 +455,7 @@ namespace Etesian {
if (_cellWidget) _cellWidget->refresh(); if (_cellWidget) _cellWidget->refresh();
_flags |= NoPlacement; _placed = true;
} }
@ -611,20 +607,22 @@ namespace Etesian {
#endif // HAVE_COLOQUINTE #endif // HAVE_COLOQUINTE
} }
void EtesianEngine::place ( unsigned int flags ) void EtesianEngine::place ()
{ {
#if HAVE_COLOQUINTE #if HAVE_COLOQUINTE
using namespace coloquinte::gp; using namespace coloquinte::gp;
using namespace coloquinte::dp; using namespace coloquinte::dp;
if (flags & SlowMotion) getConfiguration()-> setFlags( SlowMotion ); getConfiguration()->print( getCell() );
else getConfiguration()->unsetFlags( SlowMotion );
if (getCell()->getAbutmentBox().isEmpty()) setDefaultAb(); if (getCell()->getAbutmentBox().isEmpty()) setDefaultAb();
findYSpin(); findYSpin();
toColoquinte(); toColoquinte();
Effort placementEffort = getPlaceEffort();
GraphicUpdate placementUpdate = getUpdateConf();
Density densityConf = getSpreadingConf();
cmess1 << " o Running Coloquinte." << endl; cmess1 << " o Running Coloquinte." << endl;
cmess1 << " - Computing initial placement..." << endl; cmess1 << " - Computing initial placement..." << endl;
cmess2 << setfill('0') << right; cmess2 << setfill('0') << right;
@ -647,12 +645,13 @@ namespace Etesian {
cmess2 << " - Elapsed time:" << timeDelta cmess2 << " - Elapsed time:" << timeDelta
<< " HPWL:" << get_HPWL_wirelength( _circuit, _placementUB ) << " HPWL:" << get_HPWL_wirelength( _circuit, _placementUB )
<< "\n " << "\n "
<< "- Linear Disrupt.:" << get_mean_linear_disruption ( _circuit, _placementLB, _placementLB ) << "- Linear Disrupt.:" << get_mean_linear_disruption ( _circuit, _placementLB, _placementUB )
<< " Quad. Disrupt.:" << get_mean_quadratic_disruption( _circuit, _placementLB, _placementLB ) << " Quad. Disrupt.:" << get_mean_quadratic_disruption( _circuit, _placementLB, _placementUB )
<< endl; << endl;
_placementLB = _placementUB; _placementLB = _placementUB;
_placementLB.selfcheck(); _placementLB.selfcheck();
if(placementUpdate == UpdateAll)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
// Early topology-independent solution + negligible pulling forces to avoid dumb solutions // Early topology-independent solution + negligible pulling forces to avoid dumb solutions
@ -662,39 +661,50 @@ namespace Etesian {
solve_linear_system( _circuit, _placementLB, solv, 200 ); solve_linear_system( _circuit, _placementLB, solv, 200 );
_progressReport2( startTime, " [--]" ); _progressReport2( startTime, " [--]" );
if(placementUpdate <= LowerBound)
_updatePlacement( _placementLB ); _updatePlacement( _placementLB );
cmess1 << " o Simple legalization." << endl; cmess1 << " o Simple legalization." << endl;
auto snd_legalizer = region_distribution::uniform_density_distribution(_surface, _circuit, _placementLB); auto snd_legalizer = region_distribution::uniform_density_distribution(_surface, _circuit, _placementLB);
get_rough_legalization( _circuit, _placementUB, snd_legalizer); get_rough_legalization( _circuit, _placementUB, snd_legalizer);
if(placementUpdate == UpdateAll)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
int nbr_iterations = 60; int globalIterations;
float_t max_force = 1.5; if(placementEffort == Fast)
bool full_density = false; globalIterations = 40;
else if(placementEffort == Standard)
globalIterations = 70;
else if(placementEffort == High)
globalIterations = 120;
else
globalIterations = 250;
for ( int i=0; i<nbr_iterations; ++i ) { float_t maxForce = 1.0;
float_t pulling_force = (i+1) * max_force / nbr_iterations;
for ( int i=0; i<globalIterations; ++i ) {
float_t iterProp = static_cast<float_t>(i+1)/ globalIterations;
float_t pulling_force = maxForce * iterProp * iterProp; // More effort at low pulling forces
// Get the system to optimize (tolerance, maximum and minimum pin counts) // Get the system to optimize (tolerance, maximum and minimum pin counts)
// and the pulling forces (threshold distance) // and the pulling forces (threshold distance)
auto solv = get_HPWLF_linear_system ( _circuit, _placementLB, 0.5 * sliceHeight, 2, 100000 ) auto solv = get_HPWLF_linear_system ( _circuit, _placementLB, 0.5 * sliceHeight, 2, 100000 )
+ get_linear_pulling_forces( _circuit, _placementUB, _placementLB, pulling_force, 40.0 ); + get_linear_pulling_forces( _circuit, _placementUB, _placementLB, pulling_force, 40.0 );
solve_linear_system( _circuit, _placementLB, solv, 400 ); // number of iterations solve_linear_system( _circuit, _placementLB, solv, 400 ); // number of iterations
_progressReport2( startTime, " Linear." ); _progressReport2( startTime, " Linear." );
_updatePlacement( _placementLB );
// Optimize orientation sometimes // Optimize orientation sometimes
if (i%5 == 0) { if (i%5 == 0) {
optimize_exact_orientations( _circuit, _placementLB ); optimize_exact_orientations( _circuit, _placementLB );
_progressReport2( startTime, " Orient." ); _progressReport2( startTime, " Orient." );
_updatePlacement( _placementLB );
} }
if(placementUpdate <= LowerBound)
_updatePlacement( _placementLB );
// Create a legalizer and bipartition it until we have sufficient precision // Create a legalizer and bipartition it until we have sufficient precision
auto legalizer = full_density ? auto legalizer = densityConf == ForceUniform ?
region_distribution::full_density_distribution(_surface, _circuit, _placementLB) region_distribution::uniform_density_distribution(_surface, _circuit, _placementLB)
: region_distribution::uniform_density_distribution(_surface, _circuit, _placementLB); : region_distribution::full_density_distribution(_surface, _circuit, _placementLB);
for ( int quad_part=0 ; _circuit.cell_cnt() > 10 * (1 << (quad_part*2)) ; ++quad_part ) { // Until there is about 10 standard cells per region for ( int quad_part=0 ; _circuit.cell_cnt() > 10 * (1 << (quad_part*2)) ; ++quad_part ) { // Until there is about 10 standard cells per region
legalizer.x_bipartition(); legalizer.x_bipartition();
legalizer.y_bipartition(); legalizer.y_bipartition();
@ -711,57 +721,71 @@ namespace Etesian {
label.str(""); label.str("");
label << " [" << setw(2) << setfill('0') << i << "] Bipart."; label << " [" << setw(2) << setfill('0') << i << "] Bipart.";
_progressReport1( startTime, label.str() ); _progressReport1( startTime, label.str() );
if(placementUpdate == UpdateAll)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
if (i >= 2*nbr_iterations/3) { if (i >= 2*globalIterations/3) {
auto prec_legalizer = legalize( _circuit, _placementUB, _surface, sliceHeight ); auto prec_legalizer = legalize( _circuit, _placementUB, _surface, sliceHeight );
coloquinte::dp::get_result( _circuit, prec_legalizer, _placementUB ); coloquinte::dp::get_result( _circuit, prec_legalizer, _placementUB );
_progressReport1( startTime, " Legal. " ); _progressReport1( startTime, " Legal. " );
if(placementUpdate == UpdateAll)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
} }
} }
cmess1 << " o Detailed Placement." << endl; cmess1 << " o Detailed Placement." << endl;
index_t legalizeIterations = 3; index_t detailedIterations;
for ( index_t i=0; i<legalizeIterations; ++i ){ if(placementEffort == Fast)
detailedIterations = 1;
else if(placementEffort == Standard)
detailedIterations = 3;
else if(placementEffort == High)
detailedIterations = 7;
else
detailedIterations = 15;
for ( index_t i=0; i<detailedIterations; ++i ){
ostringstream label; ostringstream label;
label.str(""); label.str("");
label << " [" << setw(2) << setfill('0') << i << "]"; label << " [" << setw(2) << setfill('0') << i << "]";
optimize_exact_orientations( _circuit, _placementUB ); optimize_exact_orientations( _circuit, _placementUB );
_progressReport1( startTime, label.str()+" Oriented ......." ); _progressReport1( startTime, label.str()+" Oriented ......." );
if(placementUpdate <= LowerBound)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
auto legalizer = legalize( _circuit, _placementUB, _surface, sliceHeight ); auto legalizer = legalize( _circuit, _placementUB, _surface, sliceHeight );
coloquinte::dp::get_result( _circuit, legalizer, _placementUB ); coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
_progressReport1( startTime, " Legalized ......" ); _progressReport1( startTime, " Legalized ......" );
if(placementUpdate <= LowerBound)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
swaps_global_HPWL( _circuit, legalizer, 3, 4 ); swaps_global_HPWL( _circuit, legalizer, 3, 4 );
coloquinte::dp::get_result( _circuit, legalizer, _placementUB ); coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
_progressReport1( startTime, " Global Swaps ..." ); _progressReport1( startTime, " Global Swaps ..." );
if(placementUpdate <= LowerBound)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
OSRP_convex_HPWL( _circuit, legalizer ); OSRP_convex_HPWL( _circuit, legalizer );
coloquinte::dp::get_result( _circuit, legalizer, _placementUB ); coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
_progressReport1( startTime, " Row Optimization" ); _progressReport1( startTime, " Row Optimization" );
if(placementUpdate == UpdateAll)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
swaps_row_HPWL( _circuit, legalizer, 4 ); swaps_row_HPWL( _circuit, legalizer, 4 );
coloquinte::dp::get_result( _circuit, legalizer, _placementUB ); coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
_progressReport1( startTime, " Local Swaps ...." ); _progressReport1( startTime, " Local Swaps ...." );
if(placementUpdate <= LowerBound)
_updatePlacement( _placementUB );
if (i == legalizeIterations-1) { if (i == detailedIterations-1) {
row_compatible_orientation( _circuit, legalizer, (_yspinSlice0 == 0) ); row_compatible_orientation( _circuit, legalizer, true );
coloquinte::dp::get_result( _circuit, legalizer, _placementUB ); coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
verify_placement_legality( _circuit, _placementUB, _surface ); verify_placement_legality( _circuit, _placementUB, _surface );
_progressReport1( startTime, " Final Legalize ." ); _progressReport1( startTime, " Final Legalize ." );
} }
_updatePlacement( _placementUB, (i==legalizeIterations-1) ? ForceUpdate : 0 );
} }
_updatePlacement( _placementUB );
cmess1 << " o Adding feed cells." << endl; cmess1 << " o Adding feed cells." << endl;
addFeeds(); addFeeds();
@ -774,7 +798,7 @@ namespace Etesian {
cmess1 << ::Dots::asString cmess1 << ::Dots::asString
(" - RMST", DbU::getValueString(get_RSMT_wirelength(_circuit,_placementUB )*getPitch()) ) << endl; (" - RMST", DbU::getValueString(get_RSMT_wirelength(_circuit,_placementUB )*getPitch()) ) << endl;
_flags &= ~NoPlacement; _placed = false;
#else #else
cerr << Warning("Coloquinte library wasn't found, Etesian is disabled.") << endl; cerr << Warning("Coloquinte library wasn't found, Etesian is disabled.") << endl;
#endif #endif
@ -826,11 +850,9 @@ namespace Etesian {
} }
void EtesianEngine::_updatePlacement ( const coloquinte::placement_t& placement, unsigned int flags ) void EtesianEngine::_updatePlacement ( const coloquinte::placement_t& placement )
{ {
#if HAVE_COLOQUINTE #if HAVE_COLOQUINTE
if ((not isSlowMotion()) and not (flags & ForceUpdate)) return;
UpdateSession::open(); UpdateSession::open();
forEach ( Occurrence, ioccurrence, getCell()->getLeafInstanceOccurrences() ) forEach ( Occurrence, ioccurrence, getCell()->getLeafInstanceOccurrences() )

View File

@ -99,7 +99,6 @@ namespace Etesian {
_viewer->clearToolInterrupt(); _viewer->clearToolInterrupt();
EtesianEngine* etesian = getForFramework( CreateEngine ); EtesianEngine* etesian = getForFramework( CreateEngine );
etesian->getConfiguration()->setFlags( EtesianEngine::SlowMotion );
etesian->resetPlacement(); etesian->resetPlacement();
etesian->place(); etesian->place();
} }

View File

@ -88,8 +88,6 @@ extern "C" {
PyModule_AddObject( module, "GraphicEtesianEngine", (PyObject*)&PyTypeGraphicEtesianEngine ); PyModule_AddObject( module, "GraphicEtesianEngine", (PyObject*)&PyTypeGraphicEtesianEngine );
PyEtesianEngine_postModuleInit(); PyEtesianEngine_postModuleInit();
//cerr << "std::string typeid name:" << typeid(string).name() << endl;
} }

View File

@ -101,27 +101,9 @@ extern "C" {
return PyEtesianEngine_Link(etesian); return PyEtesianEngine_Link(etesian);
} }
PyObject* PyEtesianEngine_place ( PyEtesianEngine* self, PyObject* args )
{
trace << "PyEtesianEngine_place()" << endl;
HTRY
METHOD_HEAD("EtesianEngine.place()")
unsigned int flags = 0;
if (PyArg_ParseTuple(args,"I:EtesianEngine.place", &flags)) {
etesian->place( flags );
} else {
PyErr_SetString(ConstructorError, "EtesianEngine.place(): Invalid number/bad type of parameter.");
return NULL;
}
HCATCH
Py_RETURN_NONE;
}
// Standart Accessors (Attributes). // Standart Accessors (Attributes).
DirectVoidMethod(EtesianEngine,etesian,place)
// DirectVoidMethod(EtesianEngine,etesian,runNegociate) // DirectVoidMethod(EtesianEngine,etesian,runNegociate)
// DirectVoidMethod(EtesianEngine,etesian,printConfiguration) // DirectVoidMethod(EtesianEngine,etesian,printConfiguration)
// DirectVoidMethod(EtesianEngine,etesian,saveGlobalSolution) // DirectVoidMethod(EtesianEngine,etesian,saveGlobalSolution)
@ -135,11 +117,11 @@ extern "C" {
PyMethodDef PyEtesianEngine_Methods[] = PyMethodDef PyEtesianEngine_Methods[] =
{ { "get" , (PyCFunction)PyEtesianEngine_get , METH_VARARGS|METH_STATIC { { "get" , (PyCFunction)PyEtesianEngine_get , METH_VARARGS|METH_STATIC
, "Returns the Etesian engine attached to the Cell, None if there isnt't." } , "Returns the Etesian engine attached to the Cell, None if there isn't." }
, { "create" , (PyCFunction)PyEtesianEngine_create , METH_VARARGS|METH_STATIC , { "create" , (PyCFunction)PyEtesianEngine_create , METH_VARARGS|METH_STATIC
, "Create a Etesian engine on this cell." } , "Create an Etesian engine on this cell." }
, { "place" , (PyCFunction)PyEtesianEngine_place , METH_VARARGS , { "place" , (PyCFunction)PyEtesianEngine_place , METH_NOARGS
, "Run the global router (Knik)." } , "Run the placer (Etesian)." }
, { "destroy" , (PyCFunction)PyEtesianEngine_destroy , METH_NOARGS , { "destroy" , (PyCFunction)PyEtesianEngine_destroy , METH_NOARGS
, "Destroy the associated hurricane object. The python object remains." } , "Destroy the associated hurricane object. The python object remains." }
, {NULL, NULL, 0, NULL} /* sentinel */ , {NULL, NULL, 0, NULL} /* sentinel */
@ -165,9 +147,8 @@ extern "C" {
extern void PyEtesianEngine_postModuleInit () extern void PyEtesianEngine_postModuleInit ()
{ {
PyObject* constant; //PyObject* constant;
//LoadObjectConstant(PyTypeEtesianEngine.tp_dict,EtesianEngine::SlowMotion,"SlowMotion");
LoadObjectConstant(PyTypeEtesianEngine.tp_dict,EtesianEngine::SlowMotion,"SlowMotion");
} }

View File

@ -40,68 +40,62 @@ namespace Etesian {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Class : "Etesian::Configuration" (decorator). // Class : "Etesian::Configuration".
enum Effort { Fast =1
, Standard=2
, High =3
, Extreme =4
};
enum GraphicUpdate { UpdateAll =1
, LowerBound=2
, FinalOnly =3
};
enum Density { ForceUniform=1
, MaxDensity =2
};
class Configuration { class Configuration {
public: public:
// Constructor & Destructor. // Constructor & Destructor.
virtual ~Configuration (); Configuration ( const CellGauge* cg=NULL );
virtual Configuration* clone () const = 0; ~Configuration ();
Configuration* clone () const;
// Methods. // Methods.
virtual CellGauge* getCellGauge () const = 0; inline CellGauge* getCellGauge () const;
virtual bool isSlowMotion () const = 0; inline Effort getPlaceEffort () const;
virtual void setFlags ( unsigned int ) = 0; inline GraphicUpdate getUpdateConf () const;
virtual void unsetFlags ( unsigned int ) = 0; inline Density getSpreadingConf () const;
virtual void print ( Cell* ) const = 0; inline double getSpaceMargin () const;
virtual Record* _getRecord () const = 0; inline double getAspectRatio () const;
virtual string _getString () const = 0; void print ( Cell* ) const;
virtual string _getTypeName () const = 0; Record* _getRecord () const;
protected: string _getString () const;
Configuration (); string _getTypeName () const;
private:
Configuration ( const Configuration& );
Configuration& operator= ( const Configuration& );
private:
static Configuration* _default;
};
// -------------------------------------------------------------------
// Class : "Etesian::ConfigurationConcrete".
class ConfigurationConcrete : public Configuration {
friend class Configuration;
public:
// Constructor & Destructor.
ConfigurationConcrete ( const CellGauge* cg=NULL );
virtual ~ConfigurationConcrete ();
virtual ConfigurationConcrete* clone () const;
// Methods.
virtual CellGauge* getCellGauge () const;
virtual bool isSlowMotion () const;
virtual void setFlags ( unsigned int );
virtual void unsetFlags ( unsigned int );
virtual void print ( Cell* ) const;
virtual Record* _getRecord () const;
virtual string _getString () const;
virtual string _getTypeName () const;
protected: protected:
// Attributes. // Attributes.
CellGauge* _cg; CellGauge* _cg;
unsigned int _flags; Effort _placeEffort;
GraphicUpdate _updateConf;
Density _spreadingConf;
double _spaceMargin;
double _aspectRatio;
private: private:
ConfigurationConcrete ( const ConfigurationConcrete& ); Configuration ( const Configuration& );
ConfigurationConcrete& operator= ( const ConfigurationConcrete& ); Configuration& operator= ( const Configuration& );
}; };
inline CellGauge* Configuration::getCellGauge () const { return _cg; }
inline Effort Configuration::getPlaceEffort () const { return _placeEffort; }
inline GraphicUpdate Configuration::getUpdateConf () const { return _updateConf; }
inline Density Configuration::getSpreadingConf () const { return _spreadingConf; }
inline double Configuration::getSpaceMargin () const { return _spaceMargin; }
inline double Configuration::getAspectRatio () const { return _aspectRatio; }
} // Etesian namespace. } // Etesian namespace.
INSPECTOR_P_SUPPORT(Etesian::Configuration); INSPECTOR_P_SUPPORT(Etesian::Configuration);
INSPECTOR_P_SUPPORT(Etesian::ConfigurationConcrete);
#endif // ETESIAN_CONFIGURATION_H #endif // ETESIAN_CONFIGURATION_H

View File

@ -52,24 +52,22 @@ namespace Etesian {
class EtesianEngine : public CRL::ToolEngine { class EtesianEngine : public CRL::ToolEngine {
public: public:
enum Flag { NoPlacement=0x0001
, FlatDesign =0x0002
, ForceUpdate=0x0004
, YSpinSet =0x0008
, SlowMotion =0x0010
};
public: public:
static const Name& staticGetName (); static const Name& staticGetName ();
static EtesianEngine* create ( Cell* ); static EtesianEngine* create ( Cell* );
static EtesianEngine* get ( const Cell* ); static EtesianEngine* get ( const Cell* );
public: public:
inline bool isSlowMotion () const;
virtual Configuration* getConfiguration (); virtual Configuration* getConfiguration ();
virtual const Configuration* getConfiguration () const; virtual const Configuration* getConfiguration () const;
virtual const Name& getName () const; virtual const Name& getName () const;
inline CellGauge* getCellGauge () const; inline CellGauge* getCellGauge () const;
inline DbU::Unit getPitch () const; inline DbU::Unit getPitch () const;
inline DbU::Unit getSliceHeight () const; inline DbU::Unit getSliceHeight () const;
inline Effort getPlaceEffort () const;
inline GraphicUpdate getUpdateConf () const;
inline Density getSpreadingConf () const;
inline double getSpaceMargin () const;
inline double getAspectRatio () const;
inline const FeedCells& getFeedCells () const; inline const FeedCells& getFeedCells () const;
inline void setCellWidget ( Hurricane::CellWidget* ); inline void setCellWidget ( Hurricane::CellWidget* );
void startMeasures (); void startMeasures ();
@ -78,7 +76,7 @@ namespace Etesian {
void setDefaultAb (); void setDefaultAb ();
void resetPlacement (); void resetPlacement ();
void toColoquinte (); void toColoquinte ();
void place ( unsigned int flags=SlowMotion ); void place ();
inline void useFeed ( Cell* ); inline void useFeed ( Cell* );
size_t findYSpin (); size_t findYSpin ();
void addFeeds (); void addFeeds ();
@ -91,7 +89,9 @@ namespace Etesian {
static Name _toolName; static Name _toolName;
protected: protected:
Configuration* _configuration; Configuration* _configuration;
unsigned int _flags; bool _placed;
bool _ySpinSet;
bool _flatDesign;
Timer _timer; Timer _timer;
coloquinte::box<coloquinte::int_t> _surface; coloquinte::box<coloquinte::int_t> _surface;
coloquinte::netlist _circuit; coloquinte::netlist _circuit;
@ -113,18 +113,22 @@ namespace Etesian {
EtesianEngine ( const EtesianEngine& ); EtesianEngine ( const EtesianEngine& );
EtesianEngine& operator= ( const EtesianEngine& ); EtesianEngine& operator= ( const EtesianEngine& );
private: private:
void _updatePlacement ( const coloquinte::placement_t&, unsigned int flags=0 ); void _updatePlacement ( const coloquinte::placement_t& );
void _progressReport1 ( time_t startTime, string label ) const; void _progressReport1 ( time_t startTime, string label ) const;
void _progressReport2 ( time_t startTime, string label ) const; void _progressReport2 ( time_t startTime, string label ) const;
}; };
// Inline Functions. // Inline Functions.
inline bool EtesianEngine::isSlowMotion () const { return getConfiguration()->isSlowMotion(); }
inline void EtesianEngine::setCellWidget ( Hurricane::CellWidget* cw ) { _cellWidget = cw; } inline void EtesianEngine::setCellWidget ( Hurricane::CellWidget* cw ) { _cellWidget = cw; }
inline CellGauge* EtesianEngine::getCellGauge () const { return getConfiguration()->getCellGauge(); } inline CellGauge* EtesianEngine::getCellGauge () const { return getConfiguration()->getCellGauge(); }
inline DbU::Unit EtesianEngine::getPitch () const { return getCellGauge()->getPitch(); } inline DbU::Unit EtesianEngine::getPitch () const { return getCellGauge()->getPitch(); }
inline DbU::Unit EtesianEngine::getSliceHeight () const { return getCellGauge()->getSliceHeight(); } inline DbU::Unit EtesianEngine::getSliceHeight () const { return getCellGauge()->getSliceHeight(); }
inline Effort EtesianEngine::getPlaceEffort () const { return getConfiguration()->getPlaceEffort(); }
inline GraphicUpdate EtesianEngine::getUpdateConf () const { return getConfiguration()->getUpdateConf(); }
inline Density EtesianEngine::getSpreadingConf () const { return getConfiguration()->getSpreadingConf(); }
inline double EtesianEngine::getSpaceMargin () const { return getConfiguration()->getSpaceMargin(); }
inline double EtesianEngine::getAspectRatio () const { return getConfiguration()->getAspectRatio(); }
inline void EtesianEngine::useFeed ( Cell* cell ) { _feedCells.useFeed(cell); } inline void EtesianEngine::useFeed ( Cell* cell ) { _feedCells.useFeed(cell); }
inline const FeedCells& EtesianEngine::getFeedCells () const { return _feedCells; } inline const FeedCells& EtesianEngine::getFeedCells () const { return _feedCells; }

View File

@ -7,7 +7,7 @@
list(INSERT CMAKE_MODULE_PATH 0 "${DESTDIR}$ENV{CORIOLIS_TOP}/share/cmake/Modules/") list(INSERT CMAKE_MODULE_PATH 0 "${DESTDIR}$ENV{CORIOLIS_TOP}/share/cmake/Modules/")
find_package(Bootstrap REQUIRED) find_package(Bootstrap REQUIRED)
setup_project_paths(COLOQUINTE) setup_project_paths(IMPORTEDS)
setup_project_paths(CORIOLIS) setup_project_paths(CORIOLIS)
set_cmake_policies() set_cmake_policies()

View File

@ -44,15 +44,13 @@ def credits ():
s = '' s = ''
s += ' Tool Credits\n' s += ' Tool Credits\n'
s += ' Hurricane .................... Remy Escassut & Christian Masson\n' s += ' Hurricane .................... Remy Escassut & Christian Masson\n'
s += ' Nimbus - Infrastructure .......................... Hugo Clement\n' s += ' Etesian - Placer .............................. Gabriel Gouvine\n'
s += ' Mauka - Placer ........................... Christophe Alexandre\n'
s += ' Knik - Global Router ............................ Damien Dupuis\n' s += ' Knik - Global Router ............................ Damien Dupuis\n'
s += ' Kite - Detailed Router ....................... Jean-Paul Chaput\n\n' s += ' Kite - Detailed Router ....................... Jean-Paul Chaput\n\n'
s += ' hMETIS software credits (used by Mauka)\n' s += ' Coloquinte software credits (used by Etesian)\n'
s += ' Author ........................................ Georges Karypis\n' s += ' Author ........................................ Gabriel Gouvine\n'
s += ' Prof. Ident. .......................... University of Minnesota\n' s += ' URL .............. https://github.com/Coloquinte/Coloquinte.git\n\n'
s += ' URL .......................... http://glaros.dtc.umn.edu/gkhome\n\n'
s += ' FLUTE software credits (used by Knik)\n' s += ' FLUTE software credits (used by Knik)\n'
s += ' Author ........................................ Chris C. N. CHU\n' s += ' Author ........................................ Chris C. N. CHU\n'