Add basic yosys (nopy), klayout scripts and command support to designflow.
* New: In cumulus.designflow: add yosysnp to manage Yosys without Python support enabled. Add klayout support for running scripts in batch mode. Add generic system command support. * Change: In cumulus.designflow.task.TaskFlow, systematically convert pathes (str) into pathlib.Path in targets and depends. * New: In cumulus.designflow.clean.Clean, add cleaning by glob.
This commit is contained in:
parent
5546c2d89f
commit
50937d69c7
|
@ -16,8 +16,11 @@
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/graal.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/dreal.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/yosys.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/yosysnp.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/blif2vst.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/pnr.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/klayout.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/command.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/clean.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/alias.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/technos.py
|
||||
|
|
|
@ -7,12 +7,16 @@ class BadAliasDepend ( Exception ): pass
|
|||
|
||||
|
||||
class Alias ( FlowTask ):
|
||||
"""
|
||||
Create an alias for a rule. Takes only two arguments, the aliased name
|
||||
of the rule and the original rule itself.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def mkRule ( rule, depends=[] ):
|
||||
return Alias( rule, depends )
|
||||
|
||||
def __init__ ( self, rule, depends, ):
|
||||
def __init__ ( self, rule, depends ):
|
||||
if len(depends) != 1:
|
||||
raise BadAliasDepend( 'Alias.__init__(): There must be exactly *one* dependency ({})' \
|
||||
.format( depends ))
|
||||
|
|
|
@ -21,9 +21,9 @@ class Asimut ( FlowTask ):
|
|||
|
||||
def __init__ ( self, rule, targets, depends, flags ):
|
||||
super().__init__( rule, targets, depends )
|
||||
self.vhdlFile = Path( self.file_depend(0) )
|
||||
self.patFile = Path( self.file_depend(1) )
|
||||
self.simFile = Path( self.targets[0] )
|
||||
self.vhdlFile = self.file_depend(0)
|
||||
self.patFile = self.file_depend(1)
|
||||
self.simFile = self.targets[0]
|
||||
self.command = [ 'asimut' ]
|
||||
if flags & Asimut.RootIsBehavioral: self.command.append( '-b' )
|
||||
if flags & Asimut.UseBdd: self.command.append( '-bdd' )
|
||||
|
|
|
@ -37,18 +37,20 @@ class Blif2Vst ( FlowTask ):
|
|||
def __init__ ( self, rule, targets, depends, flags ):
|
||||
super().__init__( rule, targets, depends )
|
||||
self.flags = flags
|
||||
if not self.targets[0].endswith('.vst'):
|
||||
if not self.targets[0].suffix == '.vst':
|
||||
raise TargetNotVst( 'Blif2Vst.__init__(): First target *must* "{}" be a vst file.' \
|
||||
.format( self.targets[0] ))
|
||||
self.addClean( self.targets )
|
||||
|
||||
def __repr__ ( self ):
|
||||
for d in self.file_dep:
|
||||
print( d )
|
||||
return '<blif2vst {} depends=[{}]>' \
|
||||
.format( self.design, ','.join(self.file_dep) )
|
||||
.format( self.design, ','.join([f.as_posix() for f in self.file_dep]) )
|
||||
|
||||
@property
|
||||
def design ( self ):
|
||||
if len(self.targets): return self.targets[0][:-4]
|
||||
if len(self.targets): return self.targets[0].stem
|
||||
return None
|
||||
|
||||
def doTask ( self ):
|
||||
|
@ -60,7 +62,7 @@ class Blif2Vst ( FlowTask ):
|
|||
|
||||
print( 'Blif2Vst.doTask() on "{}"'.format( self.design ))
|
||||
views = CRL.Catalog.State.Logical | self.flags
|
||||
cell = CRL.Blif.load( self.file_depend() )
|
||||
cell = CRL.Blif.load( self.file_depend().as_posix() )
|
||||
if cell.getName() == 'top':
|
||||
print( ' o Renaming RTLIL anonymous top cell "top" into "{}".'.format(self.design) )
|
||||
cell.setName( self.design )
|
||||
|
|
|
@ -27,8 +27,8 @@ class Boog ( FlowTask ):
|
|||
def __init__ ( self, rule, targets, depends, flags ):
|
||||
super().__init__( rule, targets, depends )
|
||||
self.flags = flags
|
||||
self.inputFile = Path( self.file_depend(0) )
|
||||
self.outputFile = Path( self.targets[0] )
|
||||
self.inputFile = self.file_depend(0)
|
||||
self.outputFile = self.targets[0]
|
||||
self.command = [ 'boog' ]
|
||||
if flags & Boog.XschModeCritical: self.command += [ '-x', '0' ]
|
||||
if flags & Boog.XschModeAll: self.command += [ '-x', '1' ]
|
||||
|
@ -38,7 +38,7 @@ class Boog ( FlowTask ):
|
|||
if flags & Boog.OptimDelaysMostly: self.command += [ '-m', '3' ]
|
||||
if flags & Boog.OptimDelays: self.command += [ '-m', '4' ]
|
||||
self.command += [ self.inputFile.stem, self.outputFile.stem ]
|
||||
self.targets.append( self.outputFile.stem + '.xsc' )
|
||||
self.targets.append( self.outputFile.with_suffix('.xsc') )
|
||||
self.addClean( self.targets )
|
||||
|
||||
def __repr__ ( self ):
|
||||
|
|
|
@ -24,8 +24,8 @@ class Boom ( FlowTask ):
|
|||
def __init__ ( self, rule, targets, depends, flags ):
|
||||
super().__init__( rule, targets, depends )
|
||||
self.flags = flags
|
||||
self.inputFile = Path( self.file_depend(0) )
|
||||
self.outputFile = Path( self.targets[0] )
|
||||
self.inputFile = self.file_depend(0)
|
||||
self.outputFile = self.targets[0]
|
||||
self.command = [ 'boom' ]
|
||||
if flags & Boom.Verbose: self.command.append( '-V' )
|
||||
if flags & Boom.TraceOn: self.command.append( '-T' )
|
||||
|
|
|
@ -10,12 +10,13 @@ class MissingTarget ( Exception ): pass
|
|||
class Clean ( FlowTask ):
|
||||
|
||||
@staticmethod
|
||||
def mkRule ( extrasClean=[] ):
|
||||
return Clean( extrasClean )
|
||||
def mkRule ( extrasClean=[], extrasGlobs=[] ):
|
||||
return Clean( extrasClean, extrasGlobs )
|
||||
|
||||
def __init__ ( self, extrasClean ):
|
||||
def __init__ ( self, extrasClean, extrasGlobs ):
|
||||
super().__init__( 'clean_flow', [], [] )
|
||||
self.extrasClean = extrasClean
|
||||
self.extrasClean = FlowTask._normFileList( extrasClean )
|
||||
self.extrasGlobs = extrasGlobs
|
||||
|
||||
def __repr__ ( self ):
|
||||
return '<clean>'
|
||||
|
@ -23,8 +24,7 @@ class Clean ( FlowTask ):
|
|||
def doTask ( self, doExtrasClean ):
|
||||
print( ' Removing all target files' )
|
||||
print( ' =========================' )
|
||||
for fileName in FlowTask.cleanTargets:
|
||||
filePath = Path( fileName )
|
||||
for filePath in FlowTask.cleanTargets:
|
||||
if filePath.is_file():
|
||||
print( ' - {:<40} [removed]'.format( filePath.as_posix() ))
|
||||
filePath.unlink()
|
||||
|
@ -33,13 +33,20 @@ class Clean ( FlowTask ):
|
|||
if doExtrasClean and len(self.extrasClean):
|
||||
print( ' Removing extra clean files' )
|
||||
print( ' ==========================' )
|
||||
for fileName in self.extrasClean:
|
||||
filePath = Path( fileName )
|
||||
for filePath in self.extrasClean:
|
||||
if filePath.is_file():
|
||||
print( ' - {:<40} [removed]'.format( filePath.as_posix() ))
|
||||
filePath.unlink()
|
||||
else:
|
||||
print( ' - {}'.format( filePath.as_posix() ))
|
||||
if doExtrasClean and len(self.extrasGlobs):
|
||||
print( ' Removing extra clean files (by glob)' )
|
||||
print( ' ====================================' )
|
||||
for directory, glob in self.extrasGlobs:
|
||||
for filePath in Path(directory).glob(glob):
|
||||
if filePath.is_file():
|
||||
print( ' - {:<40} [removed]'.format( filePath.as_posix() ))
|
||||
filePath.unlink()
|
||||
return True
|
||||
|
||||
def create_doit_tasks ( self ):
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
import os
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from doit.exceptions import TaskFailed
|
||||
from .task import FlowTask, ShellEnv
|
||||
|
||||
|
||||
class MissingTarget ( Exception ): pass
|
||||
|
||||
|
||||
class Command ( FlowTask ):
|
||||
|
||||
@staticmethod
|
||||
def mkRule ( rule, targets=[], depends=[], command=None ):
|
||||
return Command( rule, targets, depends, command )
|
||||
|
||||
def __init__ ( self, rule, targets, depends, command ):
|
||||
super().__init__( rule, targets, depends )
|
||||
self.command = command
|
||||
self.addClean( self.targets )
|
||||
|
||||
def __repr__ ( self ):
|
||||
return '<{}>'.format( ' '.join(self.command) )
|
||||
|
||||
def doTask ( self ):
|
||||
from ..helpers.io import ErrorMessage
|
||||
|
||||
state = subprocess.run( self.command )
|
||||
if state.returncode:
|
||||
e = ErrorMessage( 1, 'Command.doTask(): UNIX command failed ({}).' \
|
||||
.format( state.returncode ))
|
||||
return TaskFailed( e )
|
||||
return self.checkTargets( 'Command.doTask' )
|
||||
|
||||
def create_doit_tasks ( self ):
|
||||
return { 'basename' : self.basename
|
||||
, 'actions' : [ self.doTask ]
|
||||
, 'doc' : 'Run {}.'.format( self )
|
||||
, 'file_dep' : self.file_dep
|
||||
}
|
|
@ -17,8 +17,8 @@ class Copy ( FlowTask ):
|
|||
|
||||
def __init__ ( self, rule, targets, depends ):
|
||||
super().__init__( rule, targets, depends )
|
||||
self.sourceFile = Path( self.file_depend(0) )
|
||||
self.targetFile = Path( self.targets[0] )
|
||||
self.sourceFile = self.file_depend(0)
|
||||
self.targetFile = self.targets[0]
|
||||
self.addClean( self.targets )
|
||||
|
||||
def __repr__ ( self ):
|
||||
|
|
|
@ -25,8 +25,8 @@ class Cougar ( FlowTask ):
|
|||
def __init__ ( self, rule, targets, depends, flags ):
|
||||
super().__init__( rule, targets, depends )
|
||||
self.flags = flags
|
||||
self.inputFile = Path( self.file_depend(0) )
|
||||
self.outputFile = Path( self.targets[0] )
|
||||
self.inputFile = self.file_depend(0)
|
||||
self.outputFile = self.targets[0]
|
||||
self.command = [ 'cougar' ]
|
||||
if flags & Cougar.Transistor: self.command.append( '-t' )
|
||||
if flags & Cougar.Flatten: self.command.append( '-f' )
|
||||
|
|
|
@ -23,7 +23,7 @@ class Dreal ( FlowTask ):
|
|||
def __init__ ( self, rule, depends, flags ):
|
||||
super().__init__( rule, [], depends )
|
||||
self.flags = flags
|
||||
self.layoutFile = Path( self.file_depend(0) )
|
||||
self.layoutFile = self.file_depend(0)
|
||||
self.command = [ 'dreal', '-l', self.layoutFile.stem ]
|
||||
if flags & Dreal.Debug: self.command.append( '-debug' )
|
||||
if flags & Dreal.Xor: self.command.append( '-xor' )
|
||||
|
|
|
@ -20,10 +20,10 @@ class Druc ( FlowTask ):
|
|||
def __init__ ( self, rule, depends, flags ):
|
||||
super().__init__( rule, [], depends )
|
||||
self.flags = flags
|
||||
self.referenceFile = Path( self.file_depend(0) )
|
||||
self.targets = [ self.referenceFile.stem + '.drc'
|
||||
, self.referenceFile.stem + '_drc.gds'
|
||||
, self.referenceFile.stem + '_rng.gds' ]
|
||||
self.referenceFile = self.file_depend(0)
|
||||
self.targets = [ self.referenceFile.with_suffix('.drc')
|
||||
, Path(self.referenceFile.stem + '_drc.gds')
|
||||
, Path(self.referenceFile.stem + '_rng.gds') ]
|
||||
self.command = [ 'druc', self.referenceFile.stem ]
|
||||
if flags & Druc.Verbose: self.command.append( '-v' )
|
||||
self.addClean( self.targets )
|
||||
|
|
|
@ -22,14 +22,14 @@ class Flatph ( FlowTask ):
|
|||
super().__init__( rule, targets, depends )
|
||||
self.flags = flags
|
||||
self.instFile = None
|
||||
self.hierFile = Path( self.file_depend(0) )
|
||||
self.flatFile = Path( self.targets[0] )
|
||||
self.hierFile = self.file_depend(0)
|
||||
self.flatFile = self.targets[0]
|
||||
self.command = [ 'flatph' ]
|
||||
if flags & Flatph.Transistor: self.command.append( '-t' )
|
||||
if flags & Flatph.Catalog: self.command.append( '-r' )
|
||||
self.command.append( self.hierFile.stem )
|
||||
if len(self.targets) > 1:
|
||||
self.instFile = Path( self.targets[1] )
|
||||
self.instFile = self.targets[1]
|
||||
self.command.append( self.instFile.stem )
|
||||
self.command.append( self.flatFile.stem )
|
||||
self.addClean( self.targets )
|
||||
|
|
|
@ -17,8 +17,8 @@ class Genpat ( FlowTask ):
|
|||
|
||||
def __init__ ( self, rule, targets, depends, flags ):
|
||||
super().__init__( rule, targets, depends )
|
||||
self.inputFile = Path( self.file_depend(0) )
|
||||
self.outputFile = Path( self.targets[0] )
|
||||
self.inputFile = self.file_depend(0)
|
||||
self.outputFile = self.targets[0]
|
||||
self.command = [ 'genpat' ]
|
||||
self.command += [ self.inputFile.stem ]
|
||||
self.addClean( self.targets )
|
||||
|
|
|
@ -23,7 +23,7 @@ class Graal ( FlowTask ):
|
|||
def __init__ ( self, rule, depends, flags ):
|
||||
super().__init__( rule, [], depends )
|
||||
self.flags = flags
|
||||
self.layoutFile = Path( self.file_depend(0) )
|
||||
self.layoutFile = self.file_depend(0)
|
||||
self.command = [ 'graal', '-l', self.layoutFile.stem ]
|
||||
if flags & Graal.Debug: self.command.append( '-debug' )
|
||||
if flags & Graal.Xor: self.command.append( '-xor' )
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
import os
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from doit.exceptions import TaskFailed
|
||||
from .task import FlowTask, ShellEnv
|
||||
|
||||
|
||||
class MissingTarget ( Exception ): pass
|
||||
|
||||
|
||||
class Klayout ( FlowTask ):
|
||||
|
||||
Verbose = 0x0001
|
||||
|
||||
@staticmethod
|
||||
def mkRule ( rule, targets=[], depends=[], script=None, variables={}, flags=0 ):
|
||||
return Klayout( rule, targets, depends, script, variables, flags )
|
||||
|
||||
def __init__ ( self, rule, targets, depends, script, variables, flags ):
|
||||
depends.insert( 0, script )
|
||||
super().__init__( rule, targets, depends )
|
||||
self.flags = flags
|
||||
self.variable = variables
|
||||
self.command = [ 'klayout' ]
|
||||
for name, value in variables.items():
|
||||
self.command += [ '-rd', '{}={}'.format(name,value) ]
|
||||
self.command += [ '-b', '-r', self.file_depend(0).as_posix() ]
|
||||
#self.addClean( self.targets )
|
||||
|
||||
def __repr__ ( self ):
|
||||
return '<{}>'.format( ' '.join(self.command) )
|
||||
|
||||
def doTask ( self ):
|
||||
from ..helpers.io import ErrorMessage
|
||||
|
||||
state = subprocess.run( self.command )
|
||||
if state.returncode:
|
||||
e = ErrorMessage( 1, 'Klayout.doTask(): UNIX command failed ({}).' \
|
||||
.format( state.returncode ))
|
||||
return TaskFailed( e )
|
||||
return self.checkTargets( 'Klayout.doTask' )
|
||||
|
||||
def create_doit_tasks ( self ):
|
||||
return { 'basename' : self.basename
|
||||
, 'actions' : [ self.doTask ]
|
||||
, 'doc' : 'Run {}.'.format( self )
|
||||
, 'file_dep' : self.file_dep
|
||||
}
|
||||
|
|
@ -27,8 +27,8 @@ class Loon ( FlowTask ):
|
|||
def __init__ ( self, rule, targets, depends, flags ):
|
||||
super().__init__( rule, targets, depends )
|
||||
self.flags = flags
|
||||
self.inputFile = Path( self.file_depend(0) )
|
||||
self.outputFile = Path( self.targets[0] )
|
||||
self.inputFile = self.file_depend(0)
|
||||
self.outputFile = self.targets[0]
|
||||
self.command = [ 'loon' ]
|
||||
#print( 'flags=0x{:08x}'.format( flags ))
|
||||
if flags & Loon.XschModeCritical: self.command += [ '-x', '0' ]
|
||||
|
@ -39,7 +39,7 @@ class Loon ( FlowTask ):
|
|||
if flags & Loon.OptimDelaysMostly: self.command += [ '-m', '3' ]
|
||||
if flags & Loon.OptimDelays: self.command += [ '-m', '4' ]
|
||||
self.command += [ self.inputFile.stem, self.outputFile.stem ]
|
||||
self.targets.append( self.outputFile.stem + '.xsc' )
|
||||
self.targets.append( self.outputFile.with_suffix('.xsc') )
|
||||
self.addClean( self.targets )
|
||||
|
||||
def __repr__ ( self ):
|
||||
|
|
|
@ -25,8 +25,8 @@ class Lvx ( FlowTask ):
|
|||
|
||||
super().__init__( rule, [], depends )
|
||||
self.flags = flags
|
||||
self.referenceFile = Path( self.file_depend(0) )
|
||||
self.checkedFile = Path( self.file_depend(1) )
|
||||
self.referenceFile = self.file_depend(0)
|
||||
self.checkedFile = self.file_depend(1)
|
||||
self.command = [ 'lvx'
|
||||
, self.referenceFile.suffix[1:]
|
||||
, self.checkedFile.suffix[1:]
|
||||
|
@ -39,7 +39,7 @@ class Lvx ( FlowTask ):
|
|||
|
||||
if self.flags & Lvx.SaveReorder:
|
||||
env = CRL.AllianceFramework.get().getEnvironment()
|
||||
self.targets = [ self.checkedFile.stem + '.' + env.getOUT_LO() ]
|
||||
self.targets = [ self.checkedFile.with_suffix('.' + env.getOUT_LO()) ]
|
||||
self.addClean( self.targets )
|
||||
|
||||
def __repr__ ( self ):
|
||||
|
|
|
@ -45,7 +45,7 @@ class PnR ( FlowTask ):
|
|||
|
||||
def __repr__ ( self ):
|
||||
return '<pnr {} depends=[{}]>' \
|
||||
.format( self.design, ','.join(self.file_dep) )
|
||||
.format( self.design, ','.join([f.as_posix() for f in self.file_dep]) )
|
||||
|
||||
@property
|
||||
def design ( self ):
|
||||
|
|
|
@ -24,8 +24,8 @@ class S2R ( FlowTask ):
|
|||
def __init__ ( self, rule, targets, depends, flags ):
|
||||
super().__init__( rule, targets, depends )
|
||||
self.flags = flags
|
||||
self.inputFile = Path( self.file_depend(0) )
|
||||
self.outputFile = Path( self.targets[0] )
|
||||
self.inputFile = self.file_depend(0)
|
||||
self.outputFile = self.targets[0]
|
||||
self.command = [ 's2r' ]
|
||||
if flags & S2R.NoDenotch: self.command.append( '-t' )
|
||||
if flags & S2R.DeleteNames: self.command.append( '-c' )
|
||||
|
|
|
@ -3,8 +3,9 @@ import os
|
|||
from pathlib import Path
|
||||
from doit.exceptions import TaskFailed
|
||||
|
||||
class BadDependency ( Exception ): pass
|
||||
class DuplicatedRule ( Exception ): pass
|
||||
class BadDependency ( Exception ): pass
|
||||
class DuplicatedRule ( Exception ): pass
|
||||
class UnsupportedFileType ( Exception ): pass
|
||||
|
||||
|
||||
class ShellEnv ( object ):
|
||||
|
@ -90,11 +91,13 @@ class FlowTask ( object ):
|
|||
``create_doit_tasks()`` method. It alows task to be chained directly
|
||||
between them instead of only through dependency/target files.
|
||||
|
||||
1. Targets management: targets are always file name, stored as strings.
|
||||
1. Targets management: targets can be passed as plain files (string)
|
||||
or pathlib.Path, but are all internally converted into Path.
|
||||
|
||||
2. Dependencies management: they can be plain files, pathlib.Path objects
|
||||
or other tasks. In the later case, the dependencies are the *targets*
|
||||
of said task, which sould be files, as stated on 1.
|
||||
of said task, which sould be pathlib.Path, as stated on 1.
|
||||
plain files are converted into pathlib.Path.
|
||||
|
||||
3. Perform an early check for homonymous tasks.
|
||||
|
||||
|
@ -105,6 +108,19 @@ class FlowTask ( object ):
|
|||
rules = {}
|
||||
cleanTargets = []
|
||||
|
||||
@staticmethod
|
||||
def _normFile ( depend ):
|
||||
if isinstance(depend,FlowTask) or isinstance(depend,Path): return depend
|
||||
if isinstance(depend,str): return Path(depend)
|
||||
raise UnsupportedFileType( 'FlowTask._normFile(): Unsupported type for "{}"'.format(depend) )
|
||||
|
||||
@staticmethod
|
||||
def _normFileList ( depends ):
|
||||
if not depends: return [];
|
||||
if isinstance(depends,list):
|
||||
return [ FlowTask._normFile(d) for d in depends ]
|
||||
return [ FlowTask._normFile(depends) ]
|
||||
|
||||
def __init__ ( self, basename, targets, depends ):
|
||||
"""
|
||||
Promote ``targets`` and ``depends`` arguments to list if needed.
|
||||
|
@ -113,12 +129,8 @@ class FlowTask ( object ):
|
|||
if FlowTask.hasRule(basename):
|
||||
raise DuplicatedRule( 'FlowTask.__init__(): Duplicated rule "{}"'.format(basename) )
|
||||
self.basename = basename
|
||||
if depends is None: self.depends = []
|
||||
elif not isinstance(depends,list): self.depends = [ depends ]
|
||||
else: self.depends = depends
|
||||
if targets is None: self.targets = []
|
||||
elif not isinstance(targets,list): self.targets = [ targets ]
|
||||
else: self.targets = targets
|
||||
self.depends = FlowTask._normFileList( depends )
|
||||
self.targets = FlowTask._normFileList( targets )
|
||||
FlowTask.rules[ self.basename ] = self
|
||||
|
||||
@staticmethod
|
||||
|
@ -130,19 +142,13 @@ class FlowTask ( object ):
|
|||
def file_dep ( self ):
|
||||
"""
|
||||
Build the list of dependencies to be passed on to doit (file_dep task dict).
|
||||
Convert back pathlib.Path object to string. If the dependency is another
|
||||
FlowTask, pass on it's own targets.
|
||||
If the dependency is another FlowTask, pass on it's own targets.
|
||||
All files are pathlib.Path.
|
||||
"""
|
||||
files = []
|
||||
for depend in self.depends:
|
||||
if isinstance(depend,str):
|
||||
files += [ depend ]
|
||||
elif isinstance(depend,Path):
|
||||
files += [ depend.as_posix() ]
|
||||
elif isinstance(depend,FlowTask):
|
||||
files += depend.targets
|
||||
else:
|
||||
raise BadDependency( 'FlowTask.file_dep(): Unsupported kind of dependency {}.'.format(depend) )
|
||||
if isinstance(depend,FlowTask): files += depend.targets
|
||||
else: files += [ depend ]
|
||||
return files
|
||||
|
||||
def file_target ( self, tindex=0 ):
|
||||
|
@ -174,8 +180,7 @@ class FlowTask ( object ):
|
|||
"""
|
||||
from ..helpers.io import ErrorMessage
|
||||
for target in self.targets:
|
||||
path = Path( target )
|
||||
if not path.is_file():
|
||||
if not target.is_file():
|
||||
e = ErrorMessage( 1, '{}(): The rule "{}" did *not* generate target "{}".' \
|
||||
.format( methodName, self.basename, target ))
|
||||
return TaskFailed( e )
|
||||
|
@ -186,6 +191,6 @@ class FlowTask ( object ):
|
|||
Add the targets list to the global list. This is a helper method
|
||||
that has to be explicitely called in derived classes.
|
||||
"""
|
||||
FlowTask.cleanTargets += targets
|
||||
FlowTask.cleanTargets += FlowTask._normFileList( targets )
|
||||
|
||||
|
||||
|
|
|
@ -23,11 +23,11 @@ class Vasy ( FlowTask ):
|
|||
def __init__ ( self, rule, targets, depends, flags ):
|
||||
super().__init__( rule, targets, depends )
|
||||
self.flags = flags
|
||||
self.vhdlFile = Path( self.file_depend(0) )
|
||||
self.vhdlFile = self.file_depend(0)
|
||||
if len(self.targets) > 1:
|
||||
self.outputFile = Path( self.targets[1].stem+'.vbe' )
|
||||
self.outputFile = self.targets[1].with_suffix('.vbe')
|
||||
else:
|
||||
self.outputFile = Path( self.targets[0] )
|
||||
self.outputFile = self.targets[0]
|
||||
self.command = [ 'vasy' ]
|
||||
if flags & Vasy.Verbose: self.command.append( '-V' )
|
||||
if flags & Vasy.UseStdLogic: self.command.append( '-S' )
|
||||
|
|
|
@ -38,11 +38,8 @@ class Yosys ( FlowTask ):
|
|||
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.top = self.main.stem
|
||||
self.targets = [ Path( self.top + '.blif') ]
|
||||
self.addClean( self.targets )
|
||||
|
||||
def __repr__ ( self ):
|
||||
|
@ -68,8 +65,8 @@ class Yosys ( FlowTask ):
|
|||
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 ))
|
||||
if design.suffix == '.v' : self._run_pass( 'read_verilog {}'.format( design.as_posix() ))
|
||||
elif design.suffix == '.il': self._run_pass( 'read_ilang {}'.format( design.as_posix() ))
|
||||
else:
|
||||
e = ErrorMessage( 1, 'Yosys._loadDesign(): Unsupported input format for "{}".'.format( design ))
|
||||
self.success = TaskFailed( e )
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
|
||||
import os.path
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from pyosys import libyosys as yosys
|
||||
from doit.exceptions import TaskFailed
|
||||
from .task import FlowTask
|
||||
|
||||
|
||||
class BadLiberty ( Exception ): pass
|
||||
|
||||
|
||||
class YosysNp ( FlowTask ):
|
||||
|
||||
FlagLog = 0x00000001
|
||||
FlagQuiet = 0x00000002
|
||||
FlagUseYoWasp = 0x00000004
|
||||
_liberty = None
|
||||
|
||||
@staticmethod
|
||||
def setLiberty ( liberty ):
|
||||
if isinstance(liberty,Path): pass
|
||||
elif isinstance(liberty,str): liberty = Path( liberty )
|
||||
else:
|
||||
raise BadLiberty( '[ERROR] YosysNp.setLiberty(): Should be <str> or <Path> ({})' \
|
||||
.format( liberty ))
|
||||
if not liberty.is_file():
|
||||
raise BadLiberty( '[ERROR] YosysNp.setLiberty(): File not found "{}"' \
|
||||
.format( liberty ))
|
||||
YosysNp._liberty = liberty
|
||||
|
||||
@staticmethod
|
||||
def mkRule ( rule, targets, depends, script, top=None, flags=0 ):
|
||||
return YosysNp( rule, targets, depends, script, top, flags )
|
||||
|
||||
def __init__ ( self, rule, targets, depends, script, top, flags ):
|
||||
self.log = None
|
||||
self.success = True
|
||||
self.script = script
|
||||
self.flags = flags
|
||||
targets = FlowTask._normFileList( targets )
|
||||
depends = FlowTask._normFileList( depends )
|
||||
if top is not None:
|
||||
self.top = top
|
||||
else:
|
||||
self.top = depends[0].stem
|
||||
if targets == []:
|
||||
targets.append( self.top + '.blif' )
|
||||
if self.flags & YosysNp.FlagLog:
|
||||
self.log = Path( self.top + '.log' )
|
||||
targets.append( self.log )
|
||||
targets.append( self.top + '.ys' )
|
||||
super().__init__( rule, targets, depends )
|
||||
self.addClean( targets )
|
||||
|
||||
def __repr__ ( self ):
|
||||
return '<yosysnp {} top={}>'.format( self.main, self.top )
|
||||
|
||||
@property
|
||||
def liberty ( self ):
|
||||
return YosysNp._liberty
|
||||
|
||||
@property
|
||||
def main ( self ):
|
||||
return self.file_depend( 0 )
|
||||
|
||||
def doTask ( self ):
|
||||
from ..helpers.io import ErrorMessage
|
||||
if self.liberty is None:
|
||||
e = ErrorMessage( 1, [ 'YosysNp.doTask(): "liberty" has not been set' ] )
|
||||
return TaskFailed( e )
|
||||
if not self.liberty.is_file():
|
||||
e = ErrorMessage( 1, [ 'YosysNp.doTask(): File not found "{}"'
|
||||
, '"{}"'.format( self.liberty.as_posix() ) ] )
|
||||
return TaskFailed( e )
|
||||
ysFile = Path(self.main).stem + '.ys'
|
||||
with open( ysFile, 'w' ) as ysFd:
|
||||
ysFd.write( self.script.format( liberty =str(self.liberty)
|
||||
, cellname=self.main.stem
|
||||
, top =self.top ))
|
||||
command = [ 'yowasp-yosys' ] if self.flags & YosysNp.FlagUseYoWasp else [ 'yosys' ]
|
||||
if self.flags & YosysNp.FlagQuiet: command += [ '-q' ]
|
||||
if self.flags & YosysNp.FlagLog: command += [ '-l', self.log.as_posix() ]
|
||||
command += [ '-s', ysFile ]
|
||||
status = subprocess.call( command )
|
||||
return status == 0
|
||||
|
||||
def create_doit_tasks ( self ):
|
||||
return { 'basename' : self.basename
|
||||
, 'actions' : [ self.doTask ]
|
||||
, 'doc' : 'Run {}.'.format( self )
|
||||
, 'file_dep' : self.file_dep
|
||||
, 'targets' : self.targets
|
||||
}
|
Loading…
Reference in New Issue