Add SystemVerilog support to designflow.yosys. Merge with YosysNp.

* New: In designflow.yosys, add support to load SystemVerilog with the
    synlig plugin (CHIPS Alliance).
      Integrate back the "non-Python" version of the task. Now switch
    automatically between Python & Non-Python based on the availability
    of the plugin. Also select between "yosys" & "yowasp-yosys".
* Change: In svase & sv2v, suppress the requirement of the *first*
    dependency file to be used as the default target. Now use the
    "top module" argument.
This commit is contained in:
Jean-Paul Chaput 2023-09-16 18:12:10 +02:00
parent e0c159c07b
commit 4398770432
5 changed files with 130 additions and 38 deletions

View File

@ -18,7 +18,6 @@
${CMAKE_CURRENT_SOURCE_DIR}/designflow/sv2v.py
${CMAKE_CURRENT_SOURCE_DIR}/designflow/svase.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

View File

@ -2,7 +2,6 @@
import os.path
import subprocess
from pathlib import Path
from pyosys import libyosys as yosys
from doit.exceptions import TaskFailed
from .task import FlowTask
@ -19,11 +18,12 @@ class Sv2v ( FlowTask ):
FlagLog = 0x00000001
@staticmethod
def mkRule ( rule, targets, depends, top=None, incdirs=[], libdirs=[], defines=[], flags=0 ):
def mkRule ( rule, targets, depends, top, incdirs=[], libdirs=[], defines=[], flags=0 ):
return Sv2v( rule, targets, depends, top, incdirs, libdirs, defines, flags )
def __init__ ( self, rule, targets, depends, top, incdirs, libdirs, defines, flags ):
self.flags = flags
self.top = top
self.incdirs = incdirs
self.libdirs = libdirs
self.defines = defines
@ -31,10 +31,6 @@ class Sv2v ( FlowTask ):
self.success = True
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 + '.v' )
#if self.flags & Sv2v.FlagLog:

View File

@ -2,7 +2,6 @@
import os.path
import subprocess
from pathlib import Path
from pyosys import libyosys as yosys
from doit.exceptions import TaskFailed
from .task import FlowTask
@ -19,11 +18,12 @@ class Svase ( FlowTask ):
FlagLog = 0x00000001
@staticmethod
def mkRule ( rule, targets, depends, top=None, incdirs=[], libdirs=[], defines=[], svargs=[], flags=0 ):
def mkRule ( rule, targets, depends, top, incdirs=[], libdirs=[], defines=[], svargs=[], flags=0 ):
return Svase( rule, targets, depends, top, incdirs, libdirs, defines, svargs, flags )
def __init__ ( self, rule, targets, depends, top, incdirs, libdirs, defines, svargs, flags ):
self.flags = flags
self.top = top
self.svargs = svargs
self.incdirs = incdirs
self.libdirs = libdirs
@ -32,10 +32,6 @@ class Svase ( FlowTask ):
self.success = True
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 + '.v' )
#if self.flags & Svase.FlagLog:

View File

@ -1,16 +1,27 @@
import os.path
import shutil
import subprocess
from pathlib import Path
from doit.exceptions import TaskFailed
from .task import FlowTask
usePyYosys = True
try:
from pyosys import libyosys as yosys
except:
usePyYosys = False
class BadLiberty ( Exception ): pass
class Yosys ( FlowTask ):
_liberty = None
FlagLog = 0x00000001
FlagQuiet = 0x00000002
FlagSystemVerilog = 0x00000004
_liberty = None
@staticmethod
def setLiberty ( liberty ):
@ -25,20 +36,58 @@ class Yosys ( FlowTask ):
Yosys._liberty = liberty
@staticmethod
def mkRule ( rule, depends, top=None, blackboxes=[], flattens=[] ):
return Yosys( rule, depends, top, blackboxes, flattens )
def mkRule ( rule
, depends
, top =None
, blackboxes=[]
, flattens =[]
, svOptions =None
, svDefines =None
, svIncdirs =None
, svLibdirs =None
, script =[]
, flags =0 ):
return Yosys( rule
, depends
, top
, blackboxes
, flattens
, svOptions
, svDefines
, svIncdirs
, svLibdirs
, script
, flags )
def __init__ ( self, rule, depends, top, blackboxes, flattens ):
def __init__ ( self, rule
, depends
, top
, blackboxes
, flattens
, svOptions
, svDefines
, svIncdirs
, svLibdirs
, script
, flags ):
super().__init__( rule, [], depends )
self.success = True
self.blackboxes = blackboxes
self.flattens = flattens
self.depends += blackboxes
self.svOptions = svOptions
self.svDefines = svDefines
self.svIncdirs = svIncdirs
self.svLibdirs = svLibdirs
self.flags = flags
self.script = script
self.success = True
if top is not None:
self.top = top
else:
self.top = self.main.stem
self.targets = [ Path( self.top + '.blif') ]
if not usePyYosys:
self.targets.append( Path( self.top + '.ys' ))
self.addClean( self.targets )
def __repr__ ( self ):
@ -53,11 +102,6 @@ class Yosys ( FlowTask ):
def main ( self ):
return self.file_depend( 0 )
def _run_pass ( self, command ):
from pyosys import libyosys as yosys
if self.success is not True: return
yosys.run_pass( command, self.tool )
def _loadDesign ( self, design ):
from ..helpers.io import ErrorMessage
if self.success is not True: return
@ -66,13 +110,45 @@ class Yosys ( FlowTask ):
self.success = TaskFailed( e )
return
design = Path( design )
if design.suffix == '.v' : self._run_pass( 'read_verilog -sv {}'.format( design.as_posix() ))
elif design.suffix == '.il': self._run_pass( 'read_ilang {}'.format( design.as_posix() ))
if design.suffix == '.v' : self.script.append( 'read_verilog -sv {}'.format( design.as_posix() ))
elif design.suffix == '.il': self.script.append( 'read_ilang {}'.format( design.as_posix() ))
else:
e = ErrorMessage( 1, 'Yosys._loadDesign(): Unsupported input format for "{}".'.format( design ))
self.success = TaskFailed( e )
return
def _loadSVDesign ( self ):
from ..helpers.io import ErrorMessage
if self.success is not True: return
self.script.append( 'plugin -i systemverilog' )
svFileArgs = ''
for svFile in self.depends:
if not isinstance(svFile,Path):
svFile = Path( svFile )
if not svFile.is_file():
print( '[WARNING] Can\'t find SV file "{}".'.format( svFile.as_posix() ))
continue
svFileArgs += ' {}'.format( svFile.as_posix() )
defineArgs = ''
for define in self.svDefines:
defineArgs += ' -D{}'.format( define )
includeArgs = ''
for incdir in self.svIncdirs:
includeArgs += ' -I{}'.format( incdir )
libArgs = ''
for libdir in self.svLibdirs:
libArgs += ' -L {}'.format( libdir )
options = ' '.join( self.svOptions )
scriptArgs = { 'options' :options
, 'defines' :defineArgs
, 'includes' :includeArgs
, 'libraries':libArgs
, 'svFiles' :svFileArgs
, 'top' : self.top }
self.script.append( 'read_systemverilog {options} -top {top} {defines} {includes} {libraries} {svFiles}' \
.format( **scriptArgs ))
def _loadBlackboxes ( self ):
if self.success is not True: return
for blackbox in self.blackboxes:
@ -81,11 +157,34 @@ class Yosys ( FlowTask ):
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 ))
self.script.append( 'flatten {}'.format( flattens ))
self.script.append( 'hierarchy -top {}'.format( self.top ))
def _runScript ( self ):
from ..helpers.io import ErrorMessage
if usePyYosys:
tool = yosys.Design()
for command in self.script:
yosys.run_pass( command, tool )
if shutil.which( 'yosys' ): command = [ 'yosys' ]
elif shutil.which( 'yowasp-yosys' ): command = [ 'yowasp-yosys' ]
else:
e = ErrorMessage( 1, [ 'Yosys._runScript(): Neither "yosys" nor "yowasp-yosys" has been found' ] )
self.success = TaskFailed( e )
return
ysFile = self.targets[-1].as_posix()
with open( ysFile, 'w' ) as ysFd:
ysFd.write( '\n'.join( self.script ).format( liberty =str(self.liberty)
, cellname=self.main.stem
, top =self.top ))
if self.flags & Yosys.FlagQuiet: command += [ '-q' ]
if self.flags & Yosys.FlagLog: command += [ '-l', self.log.as_posix() ]
command += [ '-s', ysFile ]
status = subprocess.call( command )
self.success = (status == 0)
def doTask ( self ):
from pyosys import libyosys as yosys
from ..helpers.io import ErrorMessage
if self.liberty is None:
e = ErrorMessage( 1, [ 'Yosys.doTask(): "liberty" has not been set' ] )
@ -95,17 +194,20 @@ class Yosys ( FlowTask ):
, '"{}"'.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 ))
if self.flags & Yosys.FlagSystemVerilog:
self._loadSVDesign()
else:
self._loadDesign( self.main )
self.script.append( 'hierarchy -check -top {}'.format( self.top ))
self.script.append( '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] ))
self.script.append( 'memory' )
self.script.append( 'dfflibmap -liberty {}'.format( self.liberty.as_posix() ))
self.script.append( 'abc -liberty {}'.format( self.liberty.as_posix() ))
self.script.append( 'clean')
self.script.append( 'write_blif {}'.format( self.targets[0] ))
self._runScript()
return self.success
def create_doit_tasks ( self ):

View File

@ -2,7 +2,6 @@
import os.path
import subprocess
from pathlib import Path
from pyosys import libyosys as yosys
from doit.exceptions import TaskFailed
from .task import FlowTask