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/graal.py
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/dreal.py
|
${CMAKE_CURRENT_SOURCE_DIR}/designflow/dreal.py
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/yosys.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/blif2vst.py
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/pnr.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/clean.py
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/alias.py
|
${CMAKE_CURRENT_SOURCE_DIR}/designflow/alias.py
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/designflow/technos.py
|
${CMAKE_CURRENT_SOURCE_DIR}/designflow/technos.py
|
||||||
|
|
|
@ -7,12 +7,16 @@ class BadAliasDepend ( Exception ): pass
|
||||||
|
|
||||||
|
|
||||||
class Alias ( FlowTask ):
|
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
|
@staticmethod
|
||||||
def mkRule ( rule, depends=[] ):
|
def mkRule ( rule, depends=[] ):
|
||||||
return Alias( rule, depends )
|
return Alias( rule, depends )
|
||||||
|
|
||||||
def __init__ ( self, rule, depends, ):
|
def __init__ ( self, rule, depends ):
|
||||||
if len(depends) != 1:
|
if len(depends) != 1:
|
||||||
raise BadAliasDepend( 'Alias.__init__(): There must be exactly *one* dependency ({})' \
|
raise BadAliasDepend( 'Alias.__init__(): There must be exactly *one* dependency ({})' \
|
||||||
.format( depends ))
|
.format( depends ))
|
||||||
|
|
|
@ -21,9 +21,9 @@ class Asimut ( FlowTask ):
|
||||||
|
|
||||||
def __init__ ( self, rule, targets, depends, flags ):
|
def __init__ ( self, rule, targets, depends, flags ):
|
||||||
super().__init__( rule, targets, depends )
|
super().__init__( rule, targets, depends )
|
||||||
self.vhdlFile = Path( self.file_depend(0) )
|
self.vhdlFile = self.file_depend(0)
|
||||||
self.patFile = Path( self.file_depend(1) )
|
self.patFile = self.file_depend(1)
|
||||||
self.simFile = Path( self.targets[0] )
|
self.simFile = self.targets[0]
|
||||||
self.command = [ 'asimut' ]
|
self.command = [ 'asimut' ]
|
||||||
if flags & Asimut.RootIsBehavioral: self.command.append( '-b' )
|
if flags & Asimut.RootIsBehavioral: self.command.append( '-b' )
|
||||||
if flags & Asimut.UseBdd: self.command.append( '-bdd' )
|
if flags & Asimut.UseBdd: self.command.append( '-bdd' )
|
||||||
|
|
|
@ -37,18 +37,20 @@ class Blif2Vst ( FlowTask ):
|
||||||
def __init__ ( self, rule, targets, depends, flags ):
|
def __init__ ( self, rule, targets, depends, flags ):
|
||||||
super().__init__( rule, targets, depends )
|
super().__init__( rule, targets, depends )
|
||||||
self.flags = flags
|
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.' \
|
raise TargetNotVst( 'Blif2Vst.__init__(): First target *must* "{}" be a vst file.' \
|
||||||
.format( self.targets[0] ))
|
.format( self.targets[0] ))
|
||||||
self.addClean( self.targets )
|
self.addClean( self.targets )
|
||||||
|
|
||||||
def __repr__ ( self ):
|
def __repr__ ( self ):
|
||||||
|
for d in self.file_dep:
|
||||||
|
print( d )
|
||||||
return '<blif2vst {} depends=[{}]>' \
|
return '<blif2vst {} depends=[{}]>' \
|
||||||
.format( self.design, ','.join(self.file_dep) )
|
.format( self.design, ','.join([f.as_posix() for f in self.file_dep]) )
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def design ( self ):
|
def design ( self ):
|
||||||
if len(self.targets): return self.targets[0][:-4]
|
if len(self.targets): return self.targets[0].stem
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def doTask ( self ):
|
def doTask ( self ):
|
||||||
|
@ -60,7 +62,7 @@ class Blif2Vst ( FlowTask ):
|
||||||
|
|
||||||
print( 'Blif2Vst.doTask() on "{}"'.format( self.design ))
|
print( 'Blif2Vst.doTask() on "{}"'.format( self.design ))
|
||||||
views = CRL.Catalog.State.Logical | self.flags
|
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':
|
if cell.getName() == 'top':
|
||||||
print( ' o Renaming RTLIL anonymous top cell "top" into "{}".'.format(self.design) )
|
print( ' o Renaming RTLIL anonymous top cell "top" into "{}".'.format(self.design) )
|
||||||
cell.setName( self.design )
|
cell.setName( self.design )
|
||||||
|
|
|
@ -27,8 +27,8 @@ class Boog ( FlowTask ):
|
||||||
def __init__ ( self, rule, targets, depends, flags ):
|
def __init__ ( self, rule, targets, depends, flags ):
|
||||||
super().__init__( rule, targets, depends )
|
super().__init__( rule, targets, depends )
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.inputFile = Path( self.file_depend(0) )
|
self.inputFile = self.file_depend(0)
|
||||||
self.outputFile = Path( self.targets[0] )
|
self.outputFile = self.targets[0]
|
||||||
self.command = [ 'boog' ]
|
self.command = [ 'boog' ]
|
||||||
if flags & Boog.XschModeCritical: self.command += [ '-x', '0' ]
|
if flags & Boog.XschModeCritical: self.command += [ '-x', '0' ]
|
||||||
if flags & Boog.XschModeAll: self.command += [ '-x', '1' ]
|
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.OptimDelaysMostly: self.command += [ '-m', '3' ]
|
||||||
if flags & Boog.OptimDelays: self.command += [ '-m', '4' ]
|
if flags & Boog.OptimDelays: self.command += [ '-m', '4' ]
|
||||||
self.command += [ self.inputFile.stem, self.outputFile.stem ]
|
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 )
|
self.addClean( self.targets )
|
||||||
|
|
||||||
def __repr__ ( self ):
|
def __repr__ ( self ):
|
||||||
|
|
|
@ -24,8 +24,8 @@ class Boom ( FlowTask ):
|
||||||
def __init__ ( self, rule, targets, depends, flags ):
|
def __init__ ( self, rule, targets, depends, flags ):
|
||||||
super().__init__( rule, targets, depends )
|
super().__init__( rule, targets, depends )
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.inputFile = Path( self.file_depend(0) )
|
self.inputFile = self.file_depend(0)
|
||||||
self.outputFile = Path( self.targets[0] )
|
self.outputFile = self.targets[0]
|
||||||
self.command = [ 'boom' ]
|
self.command = [ 'boom' ]
|
||||||
if flags & Boom.Verbose: self.command.append( '-V' )
|
if flags & Boom.Verbose: self.command.append( '-V' )
|
||||||
if flags & Boom.TraceOn: self.command.append( '-T' )
|
if flags & Boom.TraceOn: self.command.append( '-T' )
|
||||||
|
|
|
@ -10,12 +10,13 @@ class MissingTarget ( Exception ): pass
|
||||||
class Clean ( FlowTask ):
|
class Clean ( FlowTask ):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mkRule ( extrasClean=[] ):
|
def mkRule ( extrasClean=[], extrasGlobs=[] ):
|
||||||
return Clean( extrasClean )
|
return Clean( extrasClean, extrasGlobs )
|
||||||
|
|
||||||
def __init__ ( self, extrasClean ):
|
def __init__ ( self, extrasClean, extrasGlobs ):
|
||||||
super().__init__( 'clean_flow', [], [] )
|
super().__init__( 'clean_flow', [], [] )
|
||||||
self.extrasClean = extrasClean
|
self.extrasClean = FlowTask._normFileList( extrasClean )
|
||||||
|
self.extrasGlobs = extrasGlobs
|
||||||
|
|
||||||
def __repr__ ( self ):
|
def __repr__ ( self ):
|
||||||
return '<clean>'
|
return '<clean>'
|
||||||
|
@ -23,8 +24,7 @@ class Clean ( FlowTask ):
|
||||||
def doTask ( self, doExtrasClean ):
|
def doTask ( self, doExtrasClean ):
|
||||||
print( ' Removing all target files' )
|
print( ' Removing all target files' )
|
||||||
print( ' =========================' )
|
print( ' =========================' )
|
||||||
for fileName in FlowTask.cleanTargets:
|
for filePath in FlowTask.cleanTargets:
|
||||||
filePath = Path( fileName )
|
|
||||||
if filePath.is_file():
|
if filePath.is_file():
|
||||||
print( ' - {:<40} [removed]'.format( filePath.as_posix() ))
|
print( ' - {:<40} [removed]'.format( filePath.as_posix() ))
|
||||||
filePath.unlink()
|
filePath.unlink()
|
||||||
|
@ -33,13 +33,20 @@ class Clean ( FlowTask ):
|
||||||
if doExtrasClean and len(self.extrasClean):
|
if doExtrasClean and len(self.extrasClean):
|
||||||
print( ' Removing extra clean files' )
|
print( ' Removing extra clean files' )
|
||||||
print( ' ==========================' )
|
print( ' ==========================' )
|
||||||
for fileName in self.extrasClean:
|
for filePath in self.extrasClean:
|
||||||
filePath = Path( fileName )
|
|
||||||
if filePath.is_file():
|
if filePath.is_file():
|
||||||
print( ' - {:<40} [removed]'.format( filePath.as_posix() ))
|
print( ' - {:<40} [removed]'.format( filePath.as_posix() ))
|
||||||
filePath.unlink()
|
filePath.unlink()
|
||||||
else:
|
else:
|
||||||
print( ' - {}'.format( filePath.as_posix() ))
|
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
|
return True
|
||||||
|
|
||||||
def create_doit_tasks ( self ):
|
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 ):
|
def __init__ ( self, rule, targets, depends ):
|
||||||
super().__init__( rule, targets, depends )
|
super().__init__( rule, targets, depends )
|
||||||
self.sourceFile = Path( self.file_depend(0) )
|
self.sourceFile = self.file_depend(0)
|
||||||
self.targetFile = Path( self.targets[0] )
|
self.targetFile = self.targets[0]
|
||||||
self.addClean( self.targets )
|
self.addClean( self.targets )
|
||||||
|
|
||||||
def __repr__ ( self ):
|
def __repr__ ( self ):
|
||||||
|
|
|
@ -25,8 +25,8 @@ class Cougar ( FlowTask ):
|
||||||
def __init__ ( self, rule, targets, depends, flags ):
|
def __init__ ( self, rule, targets, depends, flags ):
|
||||||
super().__init__( rule, targets, depends )
|
super().__init__( rule, targets, depends )
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.inputFile = Path( self.file_depend(0) )
|
self.inputFile = self.file_depend(0)
|
||||||
self.outputFile = Path( self.targets[0] )
|
self.outputFile = self.targets[0]
|
||||||
self.command = [ 'cougar' ]
|
self.command = [ 'cougar' ]
|
||||||
if flags & Cougar.Transistor: self.command.append( '-t' )
|
if flags & Cougar.Transistor: self.command.append( '-t' )
|
||||||
if flags & Cougar.Flatten: self.command.append( '-f' )
|
if flags & Cougar.Flatten: self.command.append( '-f' )
|
||||||
|
|
|
@ -23,7 +23,7 @@ class Dreal ( FlowTask ):
|
||||||
def __init__ ( self, rule, depends, flags ):
|
def __init__ ( self, rule, depends, flags ):
|
||||||
super().__init__( rule, [], depends )
|
super().__init__( rule, [], depends )
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.layoutFile = Path( self.file_depend(0) )
|
self.layoutFile = self.file_depend(0)
|
||||||
self.command = [ 'dreal', '-l', self.layoutFile.stem ]
|
self.command = [ 'dreal', '-l', self.layoutFile.stem ]
|
||||||
if flags & Dreal.Debug: self.command.append( '-debug' )
|
if flags & Dreal.Debug: self.command.append( '-debug' )
|
||||||
if flags & Dreal.Xor: self.command.append( '-xor' )
|
if flags & Dreal.Xor: self.command.append( '-xor' )
|
||||||
|
|
|
@ -20,10 +20,10 @@ class Druc ( FlowTask ):
|
||||||
def __init__ ( self, rule, depends, flags ):
|
def __init__ ( self, rule, depends, flags ):
|
||||||
super().__init__( rule, [], depends )
|
super().__init__( rule, [], depends )
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.referenceFile = Path( self.file_depend(0) )
|
self.referenceFile = self.file_depend(0)
|
||||||
self.targets = [ self.referenceFile.stem + '.drc'
|
self.targets = [ self.referenceFile.with_suffix('.drc')
|
||||||
, self.referenceFile.stem + '_drc.gds'
|
, Path(self.referenceFile.stem + '_drc.gds')
|
||||||
, self.referenceFile.stem + '_rng.gds' ]
|
, Path(self.referenceFile.stem + '_rng.gds') ]
|
||||||
self.command = [ 'druc', self.referenceFile.stem ]
|
self.command = [ 'druc', self.referenceFile.stem ]
|
||||||
if flags & Druc.Verbose: self.command.append( '-v' )
|
if flags & Druc.Verbose: self.command.append( '-v' )
|
||||||
self.addClean( self.targets )
|
self.addClean( self.targets )
|
||||||
|
|
|
@ -22,14 +22,14 @@ class Flatph ( FlowTask ):
|
||||||
super().__init__( rule, targets, depends )
|
super().__init__( rule, targets, depends )
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.instFile = None
|
self.instFile = None
|
||||||
self.hierFile = Path( self.file_depend(0) )
|
self.hierFile = self.file_depend(0)
|
||||||
self.flatFile = Path( self.targets[0] )
|
self.flatFile = self.targets[0]
|
||||||
self.command = [ 'flatph' ]
|
self.command = [ 'flatph' ]
|
||||||
if flags & Flatph.Transistor: self.command.append( '-t' )
|
if flags & Flatph.Transistor: self.command.append( '-t' )
|
||||||
if flags & Flatph.Catalog: self.command.append( '-r' )
|
if flags & Flatph.Catalog: self.command.append( '-r' )
|
||||||
self.command.append( self.hierFile.stem )
|
self.command.append( self.hierFile.stem )
|
||||||
if len(self.targets) > 1:
|
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.instFile.stem )
|
||||||
self.command.append( self.flatFile.stem )
|
self.command.append( self.flatFile.stem )
|
||||||
self.addClean( self.targets )
|
self.addClean( self.targets )
|
||||||
|
|
|
@ -17,8 +17,8 @@ class Genpat ( FlowTask ):
|
||||||
|
|
||||||
def __init__ ( self, rule, targets, depends, flags ):
|
def __init__ ( self, rule, targets, depends, flags ):
|
||||||
super().__init__( rule, targets, depends )
|
super().__init__( rule, targets, depends )
|
||||||
self.inputFile = Path( self.file_depend(0) )
|
self.inputFile = self.file_depend(0)
|
||||||
self.outputFile = Path( self.targets[0] )
|
self.outputFile = self.targets[0]
|
||||||
self.command = [ 'genpat' ]
|
self.command = [ 'genpat' ]
|
||||||
self.command += [ self.inputFile.stem ]
|
self.command += [ self.inputFile.stem ]
|
||||||
self.addClean( self.targets )
|
self.addClean( self.targets )
|
||||||
|
|
|
@ -23,7 +23,7 @@ class Graal ( FlowTask ):
|
||||||
def __init__ ( self, rule, depends, flags ):
|
def __init__ ( self, rule, depends, flags ):
|
||||||
super().__init__( rule, [], depends )
|
super().__init__( rule, [], depends )
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.layoutFile = Path( self.file_depend(0) )
|
self.layoutFile = self.file_depend(0)
|
||||||
self.command = [ 'graal', '-l', self.layoutFile.stem ]
|
self.command = [ 'graal', '-l', self.layoutFile.stem ]
|
||||||
if flags & Graal.Debug: self.command.append( '-debug' )
|
if flags & Graal.Debug: self.command.append( '-debug' )
|
||||||
if flags & Graal.Xor: self.command.append( '-xor' )
|
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 ):
|
def __init__ ( self, rule, targets, depends, flags ):
|
||||||
super().__init__( rule, targets, depends )
|
super().__init__( rule, targets, depends )
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.inputFile = Path( self.file_depend(0) )
|
self.inputFile = self.file_depend(0)
|
||||||
self.outputFile = Path( self.targets[0] )
|
self.outputFile = self.targets[0]
|
||||||
self.command = [ 'loon' ]
|
self.command = [ 'loon' ]
|
||||||
#print( 'flags=0x{:08x}'.format( flags ))
|
#print( 'flags=0x{:08x}'.format( flags ))
|
||||||
if flags & Loon.XschModeCritical: self.command += [ '-x', '0' ]
|
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.OptimDelaysMostly: self.command += [ '-m', '3' ]
|
||||||
if flags & Loon.OptimDelays: self.command += [ '-m', '4' ]
|
if flags & Loon.OptimDelays: self.command += [ '-m', '4' ]
|
||||||
self.command += [ self.inputFile.stem, self.outputFile.stem ]
|
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 )
|
self.addClean( self.targets )
|
||||||
|
|
||||||
def __repr__ ( self ):
|
def __repr__ ( self ):
|
||||||
|
|
|
@ -25,8 +25,8 @@ class Lvx ( FlowTask ):
|
||||||
|
|
||||||
super().__init__( rule, [], depends )
|
super().__init__( rule, [], depends )
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.referenceFile = Path( self.file_depend(0) )
|
self.referenceFile = self.file_depend(0)
|
||||||
self.checkedFile = Path( self.file_depend(1) )
|
self.checkedFile = self.file_depend(1)
|
||||||
self.command = [ 'lvx'
|
self.command = [ 'lvx'
|
||||||
, self.referenceFile.suffix[1:]
|
, self.referenceFile.suffix[1:]
|
||||||
, self.checkedFile.suffix[1:]
|
, self.checkedFile.suffix[1:]
|
||||||
|
@ -39,7 +39,7 @@ class Lvx ( FlowTask ):
|
||||||
|
|
||||||
if self.flags & Lvx.SaveReorder:
|
if self.flags & Lvx.SaveReorder:
|
||||||
env = CRL.AllianceFramework.get().getEnvironment()
|
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 )
|
self.addClean( self.targets )
|
||||||
|
|
||||||
def __repr__ ( self ):
|
def __repr__ ( self ):
|
||||||
|
|
|
@ -45,7 +45,7 @@ class PnR ( FlowTask ):
|
||||||
|
|
||||||
def __repr__ ( self ):
|
def __repr__ ( self ):
|
||||||
return '<pnr {} depends=[{}]>' \
|
return '<pnr {} depends=[{}]>' \
|
||||||
.format( self.design, ','.join(self.file_dep) )
|
.format( self.design, ','.join([f.as_posix() for f in self.file_dep]) )
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def design ( self ):
|
def design ( self ):
|
||||||
|
|
|
@ -24,8 +24,8 @@ class S2R ( FlowTask ):
|
||||||
def __init__ ( self, rule, targets, depends, flags ):
|
def __init__ ( self, rule, targets, depends, flags ):
|
||||||
super().__init__( rule, targets, depends )
|
super().__init__( rule, targets, depends )
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.inputFile = Path( self.file_depend(0) )
|
self.inputFile = self.file_depend(0)
|
||||||
self.outputFile = Path( self.targets[0] )
|
self.outputFile = self.targets[0]
|
||||||
self.command = [ 's2r' ]
|
self.command = [ 's2r' ]
|
||||||
if flags & S2R.NoDenotch: self.command.append( '-t' )
|
if flags & S2R.NoDenotch: self.command.append( '-t' )
|
||||||
if flags & S2R.DeleteNames: self.command.append( '-c' )
|
if flags & S2R.DeleteNames: self.command.append( '-c' )
|
||||||
|
|
|
@ -3,8 +3,9 @@ import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from doit.exceptions import TaskFailed
|
from doit.exceptions import TaskFailed
|
||||||
|
|
||||||
class BadDependency ( Exception ): pass
|
class BadDependency ( Exception ): pass
|
||||||
class DuplicatedRule ( Exception ): pass
|
class DuplicatedRule ( Exception ): pass
|
||||||
|
class UnsupportedFileType ( Exception ): pass
|
||||||
|
|
||||||
|
|
||||||
class ShellEnv ( object ):
|
class ShellEnv ( object ):
|
||||||
|
@ -90,11 +91,13 @@ class FlowTask ( object ):
|
||||||
``create_doit_tasks()`` method. It alows task to be chained directly
|
``create_doit_tasks()`` method. It alows task to be chained directly
|
||||||
between them instead of only through dependency/target files.
|
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
|
2. Dependencies management: they can be plain files, pathlib.Path objects
|
||||||
or other tasks. In the later case, the dependencies are the *targets*
|
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.
|
3. Perform an early check for homonymous tasks.
|
||||||
|
|
||||||
|
@ -105,6 +108,19 @@ class FlowTask ( object ):
|
||||||
rules = {}
|
rules = {}
|
||||||
cleanTargets = []
|
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 ):
|
def __init__ ( self, basename, targets, depends ):
|
||||||
"""
|
"""
|
||||||
Promote ``targets`` and ``depends`` arguments to list if needed.
|
Promote ``targets`` and ``depends`` arguments to list if needed.
|
||||||
|
@ -113,12 +129,8 @@ class FlowTask ( object ):
|
||||||
if FlowTask.hasRule(basename):
|
if FlowTask.hasRule(basename):
|
||||||
raise DuplicatedRule( 'FlowTask.__init__(): Duplicated rule "{}"'.format(basename) )
|
raise DuplicatedRule( 'FlowTask.__init__(): Duplicated rule "{}"'.format(basename) )
|
||||||
self.basename = basename
|
self.basename = basename
|
||||||
if depends is None: self.depends = []
|
self.depends = FlowTask._normFileList( depends )
|
||||||
elif not isinstance(depends,list): self.depends = [ depends ]
|
self.targets = FlowTask._normFileList( targets )
|
||||||
else: self.depends = depends
|
|
||||||
if targets is None: self.targets = []
|
|
||||||
elif not isinstance(targets,list): self.targets = [ targets ]
|
|
||||||
else: self.targets = targets
|
|
||||||
FlowTask.rules[ self.basename ] = self
|
FlowTask.rules[ self.basename ] = self
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -130,19 +142,13 @@ class FlowTask ( object ):
|
||||||
def file_dep ( self ):
|
def file_dep ( self ):
|
||||||
"""
|
"""
|
||||||
Build the list of dependencies to be passed on to doit (file_dep task dict).
|
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
|
If the dependency is another FlowTask, pass on it's own targets.
|
||||||
FlowTask, pass on it's own targets.
|
All files are pathlib.Path.
|
||||||
"""
|
"""
|
||||||
files = []
|
files = []
|
||||||
for depend in self.depends:
|
for depend in self.depends:
|
||||||
if isinstance(depend,str):
|
if isinstance(depend,FlowTask): files += depend.targets
|
||||||
files += [ depend ]
|
else: 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) )
|
|
||||||
return files
|
return files
|
||||||
|
|
||||||
def file_target ( self, tindex=0 ):
|
def file_target ( self, tindex=0 ):
|
||||||
|
@ -174,8 +180,7 @@ class FlowTask ( object ):
|
||||||
"""
|
"""
|
||||||
from ..helpers.io import ErrorMessage
|
from ..helpers.io import ErrorMessage
|
||||||
for target in self.targets:
|
for target in self.targets:
|
||||||
path = Path( target )
|
if not target.is_file():
|
||||||
if not path.is_file():
|
|
||||||
e = ErrorMessage( 1, '{}(): The rule "{}" did *not* generate target "{}".' \
|
e = ErrorMessage( 1, '{}(): The rule "{}" did *not* generate target "{}".' \
|
||||||
.format( methodName, self.basename, target ))
|
.format( methodName, self.basename, target ))
|
||||||
return TaskFailed( e )
|
return TaskFailed( e )
|
||||||
|
@ -186,6 +191,6 @@ class FlowTask ( object ):
|
||||||
Add the targets list to the global list. This is a helper method
|
Add the targets list to the global list. This is a helper method
|
||||||
that has to be explicitely called in derived classes.
|
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 ):
|
def __init__ ( self, rule, targets, depends, flags ):
|
||||||
super().__init__( rule, targets, depends )
|
super().__init__( rule, targets, depends )
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.vhdlFile = Path( self.file_depend(0) )
|
self.vhdlFile = self.file_depend(0)
|
||||||
if len(self.targets) > 1:
|
if len(self.targets) > 1:
|
||||||
self.outputFile = Path( self.targets[1].stem+'.vbe' )
|
self.outputFile = self.targets[1].with_suffix('.vbe')
|
||||||
else:
|
else:
|
||||||
self.outputFile = Path( self.targets[0] )
|
self.outputFile = self.targets[0]
|
||||||
self.command = [ 'vasy' ]
|
self.command = [ 'vasy' ]
|
||||||
if flags & Vasy.Verbose: self.command.append( '-V' )
|
if flags & Vasy.Verbose: self.command.append( '-V' )
|
||||||
if flags & Vasy.UseStdLogic: self.command.append( '-S' )
|
if flags & Vasy.UseStdLogic: self.command.append( '-S' )
|
||||||
|
|
|
@ -38,11 +38,8 @@ class Yosys ( FlowTask ):
|
||||||
if top is not None:
|
if top is not None:
|
||||||
self.top = top
|
self.top = top
|
||||||
else:
|
else:
|
||||||
if self.main.find('.') == -1:
|
self.top = self.main.stem
|
||||||
self.top = self.main
|
self.targets = [ Path( self.top + '.blif') ]
|
||||||
else:
|
|
||||||
self.top = '.'.join( self.main.split('.')[0:-1] )
|
|
||||||
self.targets = [ self.top + '.blif' ]
|
|
||||||
self.addClean( self.targets )
|
self.addClean( self.targets )
|
||||||
|
|
||||||
def __repr__ ( self ):
|
def __repr__ ( self ):
|
||||||
|
@ -68,8 +65,8 @@ class Yosys ( FlowTask ):
|
||||||
e = ErrorMessage( 1, 'Yosys._loadDesign(): Can\'t find design file "{}".'.format( design ))
|
e = ErrorMessage( 1, 'Yosys._loadDesign(): Can\'t find design file "{}".'.format( design ))
|
||||||
self.success = TaskFailed( e )
|
self.success = TaskFailed( e )
|
||||||
return
|
return
|
||||||
if design.endswith('.v' ): self._run_pass( 'read_verilog {}'.format( design ))
|
if design.suffix == '.v' : self._run_pass( 'read_verilog {}'.format( design.as_posix() ))
|
||||||
elif design.endswith('.il'): self._run_pass( 'read_ilang {}'.format( design ))
|
elif design.suffix == '.il': self._run_pass( 'read_ilang {}'.format( design.as_posix() ))
|
||||||
else:
|
else:
|
||||||
e = ErrorMessage( 1, 'Yosys._loadDesign(): Unsupported input format for "{}".'.format( design ))
|
e = ErrorMessage( 1, 'Yosys._loadDesign(): Unsupported input format for "{}".'.format( design ))
|
||||||
self.success = TaskFailed( e )
|
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