2022-12-31 08:01:37 -06:00
|
|
|
|
|
|
|
import os.path
|
|
|
|
from pathlib import Path
|
|
|
|
from pyosys import libyosys as yosys
|
|
|
|
from doit.exceptions import TaskFailed
|
|
|
|
from .task import FlowTask
|
|
|
|
|
|
|
|
|
|
|
|
class BadLiberty ( Exception ): pass
|
|
|
|
|
|
|
|
|
|
|
|
class Yosys ( FlowTask ):
|
|
|
|
|
|
|
|
_liberty = None
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def setLiberty ( liberty ):
|
|
|
|
if isinstance(liberty,Path): pass
|
|
|
|
elif isinstance(liberty,str): liberty = Path( liberty )
|
|
|
|
else:
|
|
|
|
raise BadLiberty( '[ERROR] Yosys.setLiberty(): Should be <str> or <Path> ({})' \
|
|
|
|
.format( liberty ))
|
|
|
|
if not liberty.is_file():
|
|
|
|
raise BadLiberty( '[ERROR] Yosys.setLiberty(): File not found "{}"' \
|
|
|
|
.format( liberty ))
|
|
|
|
Yosys._liberty = liberty
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def mkRule ( rule, depends, top=None, blackboxes=[], flattens=[] ):
|
|
|
|
return Yosys( rule, depends, top, blackboxes, flattens )
|
|
|
|
|
|
|
|
def __init__ ( self, rule, depends, top, blackboxes, flattens ):
|
|
|
|
super().__init__( rule, [], depends )
|
|
|
|
self.success = True
|
|
|
|
self.blackboxes = blackboxes
|
|
|
|
self.flattens = flattens
|
|
|
|
self.depends += blackboxes
|
|
|
|
if top is not None:
|
|
|
|
self.top = top
|
|
|
|
else:
|
|
|
|
if self.main.find('.') == -1:
|
|
|
|
self.top = self.main
|
|
|
|
else:
|
|
|
|
self.top = '.'.join( self.main.split('.')[0:-1] )
|
|
|
|
self.targets = [ self.top + '.blif' ]
|
|
|
|
self.addClean( self.targets )
|
|
|
|
|
|
|
|
def __repr__ ( self ):
|
|
|
|
return '<yosys {} top={} blackboxes=[{}] flattens=[{}]>' \
|
|
|
|
.format( self.main, self.top, ','.join(self.blackboxes), ','.join(self.flattens) )
|
|
|
|
|
|
|
|
@property
|
|
|
|
def liberty ( self ):
|
|
|
|
return Yosys._liberty
|
|
|
|
|
|
|
|
@property
|
|
|
|
def main ( self ):
|
|
|
|
return self.file_depend( 0 )
|
|
|
|
|
|
|
|
def _run_pass ( self, command ):
|
|
|
|
if self.success is not True: return
|
|
|
|
yosys.run_pass( command, self.tool )
|
|
|
|
|
|
|
|
def _loadDesign ( self, design ):
|
Comprehensive reorganisation of the Python part of Coriolis.
* Move all Python stuff under a common Python namespace "coriolis".
* Instead of having a series subtrees for each tool, integrate
everything in one common tree. So now, all components can be
located either with an absolute path from "coriolis" or, inside
cross-reference themselves through relatives imports.
* As a consequence, we only need to add ".../site-packages/coriolis/"
to the PYTHONPATH, and not a whole bunch of subdirectories.
And nothing, if installed in-system.
* The tree of free technologies configuration files is also moved
below "coriolis/technos" instead of "/etc".
* Supressed "cumulus" level for the plugins.
* All python modules are rewritten using relative imports except
for the configuration files that uses absolute import as they
can be cloned outside of the tree to serve as templates.
* Change: In boostrap/FindPythonSitePackages, include "/coriolis" in
Python_CORIOLISARCH and Python_CORIOLISLIB.
Provide a Python_SITELIB *without* "/coriolis" appended.
* Change: In cumulus/plugins/__init__.loadPlugins(), must prefix modules
read in the plugins directory by "coriolis.plugins.". No longer need
to add their path to sys.path.
* Change: In crlcore/python/technos/nodeX/*/devices.py, the scripts of
the layouts generators must be prefixed by "coriolis.oroshi.".
* Change: In CRL::System CTOR, no longer add the pathes of the various
plugins to sys.path. Only "site-packages/coriolis/".
* New: In Utilities::Path::toPyModePath(), new method to convert a
filesystem path into a python module path.
Examples:
"coriolis/plugins/block" --> "coriolis.plugins.block".
"coriolis/plugins/rsave.py" --> "coriolis.plugins.rsave".
* Change: In katanaEngine::_runKatanaEngine(), rename the hook script
initHook.py. No longer need to modify sys.path.
* Change: In BoraEngine::_runBoraEngine(), rename the hook script
initHook.py. No longer need to modify sys.path.
* Change: In UnicornGui::_runUnicornInit(), rename the hook script
initHook.py. No longer need to modify sys.path.
* Change: In cumulus.plugins.chip.constants, put the constants
outside __init__.py to avoid a loop at initialization.
2023-02-27 15:14:32 -06:00
|
|
|
from ..helpers.io import ErrorMessage
|
2022-12-31 08:01:37 -06:00
|
|
|
if self.success is not True: return
|
|
|
|
if not os.path.isfile(design):
|
|
|
|
e = ErrorMessage( 1, 'Yosys._loadDesign(): Can\'t find design file "{}".'.format( design ))
|
|
|
|
self.success = TaskFailed( e )
|
|
|
|
return
|
|
|
|
if design.endswith('.v' ): self._run_pass( 'read_verilog {}'.format( design ))
|
|
|
|
elif design.endswith('.il'): self._run_pass( 'read_ilang {}'.format( design ))
|
|
|
|
else:
|
|
|
|
e = ErrorMessage( 1, 'Yosys._loadDesign(): Unsupported input format for "{}".'.format( design ))
|
|
|
|
self.success = TaskFailed( e )
|
|
|
|
return
|
|
|
|
|
|
|
|
def _loadBlackboxes ( self ):
|
|
|
|
if self.success is not True: return
|
|
|
|
for blackbox in self.blackboxes:
|
|
|
|
self._loadDesign( blackbox )
|
|
|
|
|
|
|
|
def _doFlattens ( self ):
|
|
|
|
if self.success is not True: return
|
|
|
|
flattens = ' '.join( self.flattens )
|
|
|
|
self._run_pass( 'flatten {}\n'.format( flattens ))
|
|
|
|
self._run_pass( 'hierarchy -top {}\n'.format( self.top ))
|
|
|
|
|
|
|
|
def doTask ( self ):
|
Comprehensive reorganisation of the Python part of Coriolis.
* Move all Python stuff under a common Python namespace "coriolis".
* Instead of having a series subtrees for each tool, integrate
everything in one common tree. So now, all components can be
located either with an absolute path from "coriolis" or, inside
cross-reference themselves through relatives imports.
* As a consequence, we only need to add ".../site-packages/coriolis/"
to the PYTHONPATH, and not a whole bunch of subdirectories.
And nothing, if installed in-system.
* The tree of free technologies configuration files is also moved
below "coriolis/technos" instead of "/etc".
* Supressed "cumulus" level for the plugins.
* All python modules are rewritten using relative imports except
for the configuration files that uses absolute import as they
can be cloned outside of the tree to serve as templates.
* Change: In boostrap/FindPythonSitePackages, include "/coriolis" in
Python_CORIOLISARCH and Python_CORIOLISLIB.
Provide a Python_SITELIB *without* "/coriolis" appended.
* Change: In cumulus/plugins/__init__.loadPlugins(), must prefix modules
read in the plugins directory by "coriolis.plugins.". No longer need
to add their path to sys.path.
* Change: In crlcore/python/technos/nodeX/*/devices.py, the scripts of
the layouts generators must be prefixed by "coriolis.oroshi.".
* Change: In CRL::System CTOR, no longer add the pathes of the various
plugins to sys.path. Only "site-packages/coriolis/".
* New: In Utilities::Path::toPyModePath(), new method to convert a
filesystem path into a python module path.
Examples:
"coriolis/plugins/block" --> "coriolis.plugins.block".
"coriolis/plugins/rsave.py" --> "coriolis.plugins.rsave".
* Change: In katanaEngine::_runKatanaEngine(), rename the hook script
initHook.py. No longer need to modify sys.path.
* Change: In BoraEngine::_runBoraEngine(), rename the hook script
initHook.py. No longer need to modify sys.path.
* Change: In UnicornGui::_runUnicornInit(), rename the hook script
initHook.py. No longer need to modify sys.path.
* Change: In cumulus.plugins.chip.constants, put the constants
outside __init__.py to avoid a loop at initialization.
2023-02-27 15:14:32 -06:00
|
|
|
from ..helpers.io import ErrorMessage
|
2022-12-31 08:01:37 -06:00
|
|
|
if self.liberty is None:
|
|
|
|
e = ErrorMessage( 1, [ 'Yosys.doTask(): "liberty" has not been set' ] )
|
|
|
|
return TaskFailed( e )
|
|
|
|
if not self.liberty.is_file():
|
|
|
|
e = ErrorMessage( 1, [ 'Yosys.doTask(): File not found "{}"'
|
|
|
|
, '"{}"'.format( self.liberty.as_posix() ) ] )
|
|
|
|
return TaskFailed( e )
|
|
|
|
#print( 'Yosys.doTask() on "{}"'.format( self.design ))
|
|
|
|
self.tool = yosys.Design()
|
|
|
|
self._loadBlackboxes()
|
|
|
|
self._loadDesign( self.main )
|
|
|
|
self._run_pass( 'hierarchy -check -top {}'.format( self.top ))
|
|
|
|
self._run_pass( 'synth -top {}'.format( self.top ))
|
|
|
|
self._doFlattens()
|
|
|
|
self._run_pass( 'memory' )
|
|
|
|
self._run_pass( 'dfflibmap -liberty {}'.format( self.liberty.as_posix() ))
|
|
|
|
self._run_pass( 'abc -liberty {}'.format( self.liberty.as_posix() ))
|
|
|
|
self._run_pass( 'clean' )
|
|
|
|
self._run_pass( 'write_blif {}'.format( self.targets[0] ))
|
|
|
|
return self.success
|
|
|
|
|
|
|
|
def create_doit_tasks ( self ):
|
|
|
|
return { 'basename' : self.basename
|
|
|
|
, 'actions' : [ self.doTask ]
|
|
|
|
, 'doc' : 'Run {}.'.format( self )
|
|
|
|
, 'file_dep' : self.file_dep
|
|
|
|
, 'targets' : self.targets
|
|
|
|
}
|