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/sv2v.py
${CMAKE_CURRENT_SOURCE_DIR}/designflow/svase.py ${CMAKE_CURRENT_SOURCE_DIR}/designflow/svase.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/klayout.py

View File

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

View File

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

View File

@ -1,16 +1,27 @@
import os.path import os.path
import shutil
import subprocess
from pathlib import Path from pathlib import Path
from doit.exceptions import TaskFailed from doit.exceptions import TaskFailed
from .task import FlowTask from .task import FlowTask
usePyYosys = True
try:
from pyosys import libyosys as yosys
except:
usePyYosys = False
class BadLiberty ( Exception ): pass class BadLiberty ( Exception ): pass
class Yosys ( FlowTask ): class Yosys ( FlowTask ):
_liberty = None FlagLog = 0x00000001
FlagQuiet = 0x00000002
FlagSystemVerilog = 0x00000004
_liberty = None
@staticmethod @staticmethod
def setLiberty ( liberty ): def setLiberty ( liberty ):
@ -25,20 +36,58 @@ class Yosys ( FlowTask ):
Yosys._liberty = liberty Yosys._liberty = liberty
@staticmethod @staticmethod
def mkRule ( rule, depends, top=None, blackboxes=[], flattens=[] ): def mkRule ( rule
return Yosys( rule, depends, top, blackboxes, flattens ) , 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 ) super().__init__( rule, [], depends )
self.success = True
self.blackboxes = blackboxes self.blackboxes = blackboxes
self.flattens = flattens self.flattens = flattens
self.depends += blackboxes 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: if top is not None:
self.top = top self.top = top
else: else:
self.top = self.main.stem self.top = self.main.stem
self.targets = [ Path( self.top + '.blif') ] self.targets = [ Path( self.top + '.blif') ]
if not usePyYosys:
self.targets.append( Path( self.top + '.ys' ))
self.addClean( self.targets ) self.addClean( self.targets )
def __repr__ ( self ): def __repr__ ( self ):
@ -53,11 +102,6 @@ class Yosys ( FlowTask ):
def main ( self ): def main ( self ):
return self.file_depend( 0 ) 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 ): def _loadDesign ( self, design ):
from ..helpers.io import ErrorMessage from ..helpers.io import ErrorMessage
if self.success is not True: return if self.success is not True: return
@ -66,13 +110,45 @@ class Yosys ( FlowTask ):
self.success = TaskFailed( e ) self.success = TaskFailed( e )
return return
design = Path( design ) design = Path( design )
if design.suffix == '.v' : self._run_pass( 'read_verilog -sv {}'.format( design.as_posix() )) if design.suffix == '.v' : self.script.append( 'read_verilog -sv {}'.format( design.as_posix() ))
elif design.suffix == '.il': self._run_pass( 'read_ilang {}'.format( design.as_posix() )) elif design.suffix == '.il': self.script.append( '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 )
return 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 ): def _loadBlackboxes ( self ):
if self.success is not True: return if self.success is not True: return
for blackbox in self.blackboxes: for blackbox in self.blackboxes:
@ -81,11 +157,34 @@ class Yosys ( FlowTask ):
def _doFlattens ( self ): def _doFlattens ( self ):
if self.success is not True: return if self.success is not True: return
flattens = ' '.join( self.flattens ) flattens = ' '.join( self.flattens )
self._run_pass( 'flatten {}\n'.format( flattens )) self.script.append( 'flatten {}'.format( flattens ))
self._run_pass( 'hierarchy -top {}\n'.format( self.top )) 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 ): def doTask ( self ):
from pyosys import libyosys as yosys
from ..helpers.io import ErrorMessage from ..helpers.io import ErrorMessage
if self.liberty is None: if self.liberty is None:
e = ErrorMessage( 1, [ 'Yosys.doTask(): "liberty" has not been set' ] ) e = ErrorMessage( 1, [ 'Yosys.doTask(): "liberty" has not been set' ] )
@ -95,17 +194,20 @@ class Yosys ( FlowTask ):
, '"{}"'.format( self.liberty.as_posix() ) ] ) , '"{}"'.format( self.liberty.as_posix() ) ] )
return TaskFailed( e ) return TaskFailed( e )
#print( 'Yosys.doTask() on "{}"'.format( self.design )) #print( 'Yosys.doTask() on "{}"'.format( self.design ))
self.tool = yosys.Design()
self._loadBlackboxes() self._loadBlackboxes()
self._loadDesign( self.main ) if self.flags & Yosys.FlagSystemVerilog:
self._run_pass( 'hierarchy -check -top {}'.format( self.top )) self._loadSVDesign()
self._run_pass( 'synth -top {}'.format( self.top )) 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._doFlattens()
self._run_pass( 'memory' ) self.script.append( 'memory' )
self._run_pass( 'dfflibmap -liberty {}'.format( self.liberty.as_posix() )) self.script.append( 'dfflibmap -liberty {}'.format( self.liberty.as_posix() ))
self._run_pass( 'abc -liberty {}'.format( self.liberty.as_posix() )) self.script.append( 'abc -liberty {}'.format( self.liberty.as_posix() ))
self._run_pass( 'clean' ) self.script.append( 'clean')
self._run_pass( 'write_blif {}'.format( self.targets[0] )) self.script.append( 'write_blif {}'.format( self.targets[0] ))
self._runScript()
return self.success return self.success
def create_doit_tasks ( self ): def create_doit_tasks ( self ):

View File

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