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:
parent
bd3984a313
commit
8566126acc
|
@ -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' }
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- Mode:Python; explicit-buffer-name: "etesian.conf<cmos>" -*-
|
||||||
|
|
||||||
|
import helpers
|
||||||
|
|
||||||
|
execfile( helpers.sysConfDir+'/common/etesian.conf' )
|
|
@ -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 ,)
|
||||||
|
)
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- Mode:Python; explicit-buffer-name: "etesian.conf<cmos>" -*-
|
||||||
|
|
||||||
|
import helpers
|
||||||
|
|
||||||
|
execfile( helpers.sysConfDir+'/common/etesian.conf' )
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- Mode:Python; explicit-buffer-name: "etesian.conf<cmos>" -*-
|
||||||
|
|
||||||
|
import helpers
|
||||||
|
|
||||||
|
execfile( helpers.sysConfDir+'/common/etesian.conf' )
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- Mode:Python; explicit-buffer-name: "etesian.conf<cmos>" -*-
|
||||||
|
|
||||||
|
import helpers
|
||||||
|
|
||||||
|
execfile( helpers.sysConfDir+'/common/etesian.conf' )
|
|
@ -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)
|
||||||
|
|
|
@ -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" )
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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> &
|
<span class="right">Rémy <span class="sc">Escassut</span> &
|
||||||
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__" :
|
||||||
ScriptMain ()
|
kw = {}
|
||||||
|
success = ScriptMain( **kw )
|
||||||
|
shellSuccess = 0
|
||||||
|
if not success: shellSuccess = 1
|
||||||
|
|
||||||
|
sys.exit( shellSuccess )
|
||||||
|
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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,13 +645,14 @@ 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();
|
||||||
|
|
||||||
_updatePlacement( _placementUB );
|
if(placementUpdate == UpdateAll)
|
||||||
|
_updatePlacement( _placementUB );
|
||||||
|
|
||||||
// Early topology-independent solution + negligible pulling forces to avoid dumb solutions
|
// Early topology-independent solution + negligible pulling forces to avoid dumb solutions
|
||||||
cmess1 << " o Star (*) Optimization." << endl;
|
cmess1 << " o Star (*) Optimization." << endl;
|
||||||
|
@ -662,39 +661,50 @@ namespace Etesian {
|
||||||
solve_linear_system( _circuit, _placementLB, solv, 200 );
|
solve_linear_system( _circuit, _placementLB, solv, 200 );
|
||||||
_progressReport2( startTime, " [--]" );
|
_progressReport2( startTime, " [--]" );
|
||||||
|
|
||||||
_updatePlacement( _placementLB );
|
if(placementUpdate <= LowerBound)
|
||||||
|
_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);
|
||||||
|
|
||||||
_updatePlacement( _placementUB );
|
if(placementUpdate == UpdateAll)
|
||||||
|
_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() );
|
||||||
_updatePlacement( _placementUB );
|
|
||||||
|
|
||||||
if (i >= 2*nbr_iterations/3) {
|
if(placementUpdate == UpdateAll)
|
||||||
|
_updatePlacement( _placementUB );
|
||||||
|
|
||||||
|
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. " );
|
||||||
_updatePlacement( _placementUB );
|
if(placementUpdate == UpdateAll)
|
||||||
|
_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)
|
||||||
ostringstream label;
|
detailedIterations = 1;
|
||||||
label.str("");
|
else if(placementEffort == Standard)
|
||||||
label << " [" << setw(2) << setfill('0') << i << "]";
|
detailedIterations = 3;
|
||||||
|
else if(placementEffort == High)
|
||||||
|
detailedIterations = 7;
|
||||||
|
else
|
||||||
|
detailedIterations = 15;
|
||||||
|
for ( index_t i=0; i<detailedIterations; ++i ){
|
||||||
|
ostringstream label;
|
||||||
|
label.str("");
|
||||||
|
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 ......." );
|
||||||
_updatePlacement( _placementUB );
|
if(placementUpdate <= LowerBound)
|
||||||
|
_updatePlacement( _placementUB );
|
||||||
|
|
||||||
auto legalizer = legalize( _circuit, _placementUB, _surface, sliceHeight );
|
auto legalizer = legalize( _circuit, _placementUB, _surface, sliceHeight );
|
||||||
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
|
||||||
_progressReport1( startTime, " Legalized ......" );
|
|
||||||
_updatePlacement( _placementUB );
|
|
||||||
|
|
||||||
swaps_global_HPWL( _circuit, legalizer, 3, 4 );
|
|
||||||
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
|
||||||
_progressReport1( startTime, " Global Swaps ..." );
|
|
||||||
_updatePlacement( _placementUB );
|
|
||||||
|
|
||||||
OSRP_convex_HPWL( _circuit, legalizer );
|
|
||||||
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
|
||||||
_progressReport1( startTime, " Row Optimization" );
|
|
||||||
_updatePlacement( _placementUB );
|
|
||||||
|
|
||||||
swaps_row_HPWL( _circuit, legalizer, 4 );
|
|
||||||
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
|
||||||
_progressReport1( startTime, " Local Swaps ...." );
|
|
||||||
|
|
||||||
if (i == legalizeIterations-1) {
|
|
||||||
row_compatible_orientation( _circuit, legalizer, (_yspinSlice0 == 0) );
|
|
||||||
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
||||||
verify_placement_legality( _circuit, _placementUB, _surface );
|
_progressReport1( startTime, " Legalized ......" );
|
||||||
_progressReport1( startTime, " Final Legalize ." );
|
if(placementUpdate <= LowerBound)
|
||||||
}
|
_updatePlacement( _placementUB );
|
||||||
|
|
||||||
_updatePlacement( _placementUB, (i==legalizeIterations-1) ? ForceUpdate : 0 );
|
swaps_global_HPWL( _circuit, legalizer, 3, 4 );
|
||||||
|
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
||||||
|
_progressReport1( startTime, " Global Swaps ..." );
|
||||||
|
if(placementUpdate <= LowerBound)
|
||||||
|
_updatePlacement( _placementUB );
|
||||||
|
|
||||||
|
OSRP_convex_HPWL( _circuit, legalizer );
|
||||||
|
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
||||||
|
_progressReport1( startTime, " Row Optimization" );
|
||||||
|
if(placementUpdate == UpdateAll)
|
||||||
|
_updatePlacement( _placementUB );
|
||||||
|
|
||||||
|
swaps_row_HPWL( _circuit, legalizer, 4 );
|
||||||
|
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
||||||
|
_progressReport1( startTime, " Local Swaps ...." );
|
||||||
|
if(placementUpdate <= LowerBound)
|
||||||
|
_updatePlacement( _placementUB );
|
||||||
|
|
||||||
|
if (i == detailedIterations-1) {
|
||||||
|
row_compatible_orientation( _circuit, legalizer, true );
|
||||||
|
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
||||||
|
verify_placement_legality( _circuit, _placementUB, _surface );
|
||||||
|
_progressReport1( startTime, " Final Legalize ." );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
_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() )
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 ();
|
||||||
// Methods.
|
Configuration* clone () const;
|
||||||
virtual CellGauge* getCellGauge () const = 0;
|
|
||||||
virtual bool isSlowMotion () const = 0;
|
|
||||||
virtual void setFlags ( unsigned int ) = 0;
|
|
||||||
virtual void unsetFlags ( unsigned int ) = 0;
|
|
||||||
virtual void print ( Cell* ) const = 0;
|
|
||||||
virtual Record* _getRecord () const = 0;
|
|
||||||
virtual string _getString () const = 0;
|
|
||||||
virtual string _getTypeName () const = 0;
|
|
||||||
protected:
|
|
||||||
Configuration ();
|
|
||||||
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.
|
// Methods.
|
||||||
virtual CellGauge* getCellGauge () const;
|
inline CellGauge* getCellGauge () const;
|
||||||
virtual bool isSlowMotion () const;
|
inline Effort getPlaceEffort () const;
|
||||||
virtual void setFlags ( unsigned int );
|
inline GraphicUpdate getUpdateConf () const;
|
||||||
virtual void unsetFlags ( unsigned int );
|
inline Density getSpreadingConf () const;
|
||||||
virtual void print ( Cell* ) const;
|
inline double getSpaceMargin () const;
|
||||||
virtual Record* _getRecord () const;
|
inline double getAspectRatio () const;
|
||||||
virtual string _getString () const;
|
void print ( Cell* ) const;
|
||||||
virtual string _getTypeName () const;
|
Record* _getRecord () const;
|
||||||
|
string _getString () const;
|
||||||
|
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
|
||||||
|
|
|
@ -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,20 +113,24 @@ 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 void EtesianEngine::useFeed ( Cell* cell ) { _feedCells.useFeed(cell); }
|
inline GraphicUpdate EtesianEngine::getUpdateConf () const { return getConfiguration()->getUpdateConf(); }
|
||||||
inline const FeedCells& EtesianEngine::getFeedCells () const { return _feedCells; }
|
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 const FeedCells& EtesianEngine::getFeedCells () const { return _feedCells; }
|
||||||
|
|
||||||
|
|
||||||
// Variables.
|
// Variables.
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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'
|
||||||
|
|
Loading…
Reference in New Issue