diff --git a/requirements.txt b/requirements.txt
index f16b079..6104395 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,3 +3,4 @@ pytest-cov>=2.6.1
pytest-xdist>=1.25.0
coveralls>=1.5.1
antlr4-python3-runtime>=4.9.1
+dataclasses
diff --git a/setup.py b/setup.py
index bb162e5..5e9528e 100755
--- a/setup.py
+++ b/setup.py
@@ -3,6 +3,4 @@
setup(name="SigasiProjectCreator",
description="Generate a Sigasi Project from your own project specifications",
url='https://github.com/sigasi/SigasiProjectCreator',
- packages=['SigasiProjectCreator'],
- package_dir={'': 'src'},
)
diff --git a/src/SigasiProjectCreator/ArgsAndFileParser.py b/src/SigasiProjectCreator/ArgsAndFileParser.py
deleted file mode 100644
index 26b7ec0..0000000
--- a/src/SigasiProjectCreator/ArgsAndFileParser.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- :copyright: (c) 2008-2023 Sigasi
- :license: BSD, see LICENSE for more details.
-"""
-import os
-import argparse
-import pathlib
-
-
-class ArgsAndFileParser:
- options = None
-
- def __init__(self, usage):
- self.parser = argparse.ArgumentParser(prog='SigasiProjectCreator')
- self.parser.add_argument('project_name', help='Project name')
- self.parser.add_argument('input_file', help='Input file or comma-separated list of input files')
- self.parser.add_argument('destination_folder', help='Root folder of created project', type=pathlib.Path,
- nargs='?')
- self.parser.add_argument('-l', '--layout', action='store', dest='layout',
- choices=['default', 'simulator'], default='default',
- help='Project layout: default (in place) or simulator (one folder per library with linked files)')
- self.parser.add_argument('--uvm', help='Add UVM to the project, using UVM from the given install path',
- dest='uvm', type=pathlib.Path)
- self.parser.add_argument('--use-uvm-home', help='Add UVM to the project. Sigasi Studio will use the UVM_HOME environment variable to find your UVM installation',
- dest='uvmhome', action='store_true')
- self.parser.add_argument('--uvmlib', help='Library in which to compile the UVM package (default `work`)',
- dest='uvmlib', default='work')
-
- def parse_args(self):
- args = self.parser.parse_args()
- if not os.path.isfile(args.input_file):
- self.parser.error('Input file does not exist')
- if args.destination_folder is not None:
- if not args.destination_folder.is_dir():
- self.parser.error('destination folder has to be a folder')
- if args.uvmhome:
- if args.uvm is not None:
- self.parser.error('Conflicting options --uvm and --use-uvm-home used')
- args.uvm = 'ENV-UVM_HOME'
- elif args.uvm is not None:
- if not os.path.isdir(args.uvm):
- self.parser.error(f'UVM home \'{args.uvm}\' must be a folder')
- if not os.path.isfile(os.path.join(args.uvm, 'src/uvm_macros.svh')):
- self.parser.error(f'Could not find uvm_macros.svh in \'{args.uvm}/src\'')
- if not os.path.isfile(os.path.join(args.uvm, 'src/uvm_pkg.sv')):
- self.parser.error(f'Could not find uvm_pkg.sv in \'{args.uvm}/src\'')
- return args
-
- def parse_args_and_file(self, parse_file):
- args = self.parse_args()
- ArgsAndFileParser.options = args
- destination = args.destination_folder if args.destination_folder is not None else os.getcwd()
- entries = parse_file(args.input_file)
- return args.project_name, args.input_file, destination, entries
-
- @staticmethod
- def get_layout_option():
- return ArgsAndFileParser.options.layout
-
- @staticmethod
- def get_uvm_option():
- return ArgsAndFileParser.options.uvm, ArgsAndFileParser.options.uvmlib
diff --git a/src/SigasiProjectCreator/ConverterHelper.py b/src/SigasiProjectCreator/ConverterHelper.py
deleted file mode 100644
index 41e0258..0000000
--- a/src/SigasiProjectCreator/ConverterHelper.py
+++ /dev/null
@@ -1,152 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- :copyright: (c) 2008-2023 Sigasi
- :license: BSD, see LICENSE for more details.
-"""
-import os
-import platform
-import subprocess
-
-from SigasiProjectCreator import absnormpath, posixpath
-from SigasiProjectCreator.Creator import SigasiProjectCreator
-from SigasiProjectCreator.ArgsAndFileParser import ArgsAndFileParser
-
-
-def get_parts(pth):
- parts = []
- while True:
- pth, last = os.path.split(pth)
- if not last:
- break
- parts.append(last)
- return parts
-
-
-def running_in_cyg_win():
- return platform.system().startswith("CYGWIN")
-
-
-def convert_cygwin_path(cygwin_path):
- cygwin_process = subprocess.Popen(['/usr/bin/cygpath', '--windows', cygwin_path], stdout=subprocess.PIPE)
- cygwin_location = cygwin_process.communicate()[0].rstrip()
- return posixpath(cygwin_location)
-
-
-def parse_and_create_project(usage, parse_file):
- parser = ArgsAndFileParser(usage)
- (project_name, _, destination, parser_output) = parser.parse_args_and_file(parse_file)
-
- verilog_includes = None
- verilog_defines = None
- linked_files = None
- if not isinstance(parser_output, dict):
- verilog_includes = parser_output.includes
- verilog_defines = parser_output.defines
- entries = parser_output.library_mapping
- if verilog_includes is not None and len(verilog_includes) > 0:
- print("Includes: " + str(verilog_includes))
- if verilog_defines is not None and len(verilog_defines) > 0:
- print("Defines: " + str(verilog_defines))
- linked_files = parser_output.linked_file_mapping
- if linked_files is not None and len(linked_files) > 0:
- print("Linked files: " + str(linked_files))
- else:
- entries = parser_output
- print("Library mapping: " + str(entries))
-
- sigasi_project_file_creator = SigasiProjectCreator(project_name)
- sigasi_project_file_creator.unmap("/")
-
- forceVHDL = False
- forceVerilog = False
- forceVUnit = False
-
- linked_folders = dict()
- abs_destination = absnormpath(destination)
- for path, library in entries.items():
- abs_path = absnormpath(path)
- relative_path = os.path.relpath(abs_path, abs_destination)
- if (not forceVerilog) and (relative_path.endswith('.v') or relative_path.endswith('.sv')):
- forceVerilog = True
- if (not forceVHDL) and (relative_path.endswith('.vhd') or relative_path.endswith('.vhdl')):
- forceVHDL = True
- if not relative_path.startswith(".."):
- sigasi_project_file_creator.add_mapping(relative_path, library)
- else:
- common_prefix = os.path.dirname(os.path.commonpath([p + os.path.sep for p in [abs_path, abs_destination]]))
- eclipse_path = os.path.relpath(abs_path, common_prefix)
- directory_name = get_parts(eclipse_path)[-1]
- if str(ArgsAndFileParser.get_layout_option()) == 'default':
- target = os.path.join(common_prefix, directory_name)
- else:
- target = 'virtual:/virtual'
-
- linked_folders[directory_name] = target
-
- sigasi_project_file_creator.add_mapping(eclipse_path, library)
- print("Linked folders: " + str(linked_folders))
-
- # Update verilog includes: if they are in a linked folder, use the link name
- if verilog_includes is not None and linked_folders:
- new_verilog_includes = []
- for include_folder in verilog_includes:
- match_found = False
- for linked_folder, dest_folder in linked_folders.items():
- abs_dest_folder = absnormpath(dest_folder)
- abs_incl_folder = absnormpath(include_folder)
- common_prefix = os.path.commonpath([abs_dest_folder, abs_incl_folder])
- if len(str(common_prefix)) > 0 and os.path.samefile(dest_folder, common_prefix):
- prefixlen = len(str(common_prefix))
- include_subpath = abs_incl_folder[prefixlen:]
- new_inlcude_path = os.path.join(linked_folder, include_subpath.lstrip('/\\'))
- new_verilog_includes.append(new_inlcude_path)
- match_found = True
- if not match_found:
- new_verilog_includes.append(include_folder)
- verilog_includes = new_verilog_includes
- print("Includes (updated): " + str(verilog_includes))
-
- # Adding custom items to libraries.
- # sigasi_project_file_creator.add_unisim("C:/xilinx/14.5/ISE_DS/ISE/vhdl/src/unisims")
- # sigasi_project_file_creator.add_unimacro("C:/xilinx/14.5/ISE_DS/ISE/vhdl/src/unimacro")
-
- for folder, location in linked_folders.items():
- if running_in_cyg_win() and not location.startswith('virtual'):
- location = convert_cygwin_path(location)
- sigasi_project_file_creator.add_link(folder, location, True)
-
- if linked_files is not None:
- for file, location in linked_files.items():
- abs_location = absnormpath(location)
- relative_location_path = make_project_location_path(os.path.relpath(abs_location, abs_destination))
- if running_in_cyg_win():
- relative_location_path = convert_cygwin_path(relative_location_path)
-
- if str(ArgsAndFileParser.get_layout_option()) == 'default':
- abs_file = absnormpath(file)
- relative_file_path = os.path.relpath(abs_file, abs_destination)
- if running_in_cyg_win():
- relative_file_path = convert_cygwin_path(relative_file_path)
- else:
- relative_file_path = file
-
- sigasi_project_file_creator.add_link(relative_file_path, relative_location_path)
-
- # For the time being, we assume that absolute paths are used here (e.g. in a simulator install tree)
- # TODO support relative paths (should be part of a more general path handling overhaul?)
- uvm_location, uvm_library = ArgsAndFileParser.get_uvm_option()
- if uvm_location is not None:
- sigasi_project_file_creator.add_uvm(uvm_location, uvm_library)
-
- sigasi_project_file_creator.write(destination, forceVHDL, forceVerilog, verilog_includes, verilog_defines,
- forceVUnit)
-
-
-def make_project_location_path(rel_path):
- parent_level = 0
- while rel_path.startswith('..'):
- parent_level += 1
- rel_path = rel_path[3::]
- if parent_level == 0:
- return 'PROJECT_LOC/' + rel_path
- return 'PARENT-' + str(parent_level) + '-PROJECT_LOC/' + rel_path
\ No newline at end of file
diff --git a/src/SigasiProjectCreator/CsvParser.py b/src/SigasiProjectCreator/CsvParser.py
index 5b09bbd..408eeba 100644
--- a/src/SigasiProjectCreator/CsvParser.py
+++ b/src/SigasiProjectCreator/CsvParser.py
@@ -4,21 +4,30 @@
:license: BSD, see LICENSE for more details.
"""
import csv
+import pathlib
-usage = """usage: %prog project-name csv-file [destination]
+from SigasiProjectCreator.ProjectFileParser import ProjectFileParser, project_file_parser, ProjectFileParserResult
-destination is the current directory by default
-example: %prog MyProjectName filelist.csv
-"""
+@project_file_parser('csv')
+class CsvParser(ProjectFileParser):
+ """CSV file"""
+ def __init__(self):
+ super().__init__()
-def parse_file(csv_file):
- entries = dict()
- with open(csv_file, 'r') as f:
- reader = csv.reader(f, skipinitialspace=True)
- for row in reader:
- if row:
- library = row[0].strip()
- path = row[1].strip()
- entries[path] = library
- return entries
+ def parse_file(self, csv_file, options=None):
+ library_mapping = dict()
+ with open(csv_file, 'r') as f:
+ reader = csv.reader(f, skipinitialspace=True)
+ for row in reader:
+ if row:
+ library = row[0].strip()
+ path = pathlib.Path(row[1].strip()).absolute().resolve()
+ if path in library_mapping:
+ if isinstance(library_mapping[path], list):
+ library_mapping[path].append(library)
+ else:
+ library_mapping[path] = [library_mapping[path], library]
+ else:
+ library_mapping[path] = library
+ return ProjectFileParserResult(library_mapping, None, None)
diff --git a/src/SigasiProjectCreator/DotF/DotFLexer.py b/src/SigasiProjectCreator/DotF/DotFLexer.py
index b72990e..9d28115 100644
--- a/src/SigasiProjectCreator/DotF/DotFLexer.py
+++ b/src/SigasiProjectCreator/DotF/DotFLexer.py
@@ -1,4 +1,4 @@
-# Generated from DotF.g4 by ANTLR 4.13.0
+# Generated from DotF.g4 by ANTLR 4.13.1
from antlr4 import *
from io import StringIO
import sys
@@ -100,7 +100,7 @@ class DotFLexer(Lexer):
def __init__(self, input=None, output:TextIO = sys.stdout):
super().__init__(input, output)
- self.checkVersion("4.13.0")
+ self.checkVersion("4.13.1")
self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache())
self._actions = None
self._predicates = None
diff --git a/src/SigasiProjectCreator/DotF/DotFListener.py b/src/SigasiProjectCreator/DotF/DotFListener.py
index 0558d43..16a93d5 100644
--- a/src/SigasiProjectCreator/DotF/DotFListener.py
+++ b/src/SigasiProjectCreator/DotF/DotFListener.py
@@ -1,4 +1,4 @@
-# Generated from DotF.g4 by ANTLR 4.13.0
+# Generated from DotF.g4 by ANTLR 4.13.1
from antlr4 import *
if "." in __name__:
from .DotFParser import DotFParser
diff --git a/src/SigasiProjectCreator/DotF/DotFParser.py b/src/SigasiProjectCreator/DotF/DotFParser.py
index e097397..bac93b3 100644
--- a/src/SigasiProjectCreator/DotF/DotFParser.py
+++ b/src/SigasiProjectCreator/DotF/DotFParser.py
@@ -1,4 +1,4 @@
-# Generated from DotF.g4 by ANTLR 4.13.0
+# Generated from DotF.g4 by ANTLR 4.13.1
# encoding: utf-8
from antlr4 import *
from io import StringIO
@@ -74,7 +74,7 @@ class DotFParser ( Parser ):
def __init__(self, input:TokenStream, output:TextIO = sys.stdout):
super().__init__(input, output)
- self.checkVersion("4.13.0")
+ self.checkVersion("4.13.1")
self._interp = ParserATNSimulator(self, self.atn, self.decisionsToDFA, self.sharedContextCache)
self._predicates = None
diff --git a/src/SigasiProjectCreator/DotF/DotFfileParser.py b/src/SigasiProjectCreator/DotF/DotFfileParser.py
index e706950..387869b 100644
--- a/src/SigasiProjectCreator/DotF/DotFfileParser.py
+++ b/src/SigasiProjectCreator/DotF/DotFfileParser.py
@@ -7,72 +7,84 @@
# 3 : input file not found
import os
-import sys
import glob
+import pathlib
import re
-from SigasiProjectCreator.ArgsAndFileParser import ArgsAndFileParser
from .parseFile import parse_dotf
-from ..convertDotFtoCsv import rebase_file
+from .. import abort_if_false
+from ..ProjectFileParser import ProjectFileParser, project_file_parser, ProjectFileParserResult
-def abspath(path):
+def is_absolute_path(path):
+ # Check for an absolute pth on Linux or Windows, or a path which starts with an environment variable
s_path = str(path)
- if s_path.startswith('\\') or s_path.startswith('/') or s_path[1] == ':' or s_path.startswith('$'):
- # this is an absolute path in Linux or Windows
+ return s_path.startswith('\\') or s_path.startswith('/') or s_path[1] == ':' or s_path.startswith('$')
+
+
+def absolute_path(path):
+ if is_absolute_path(path):
+ return path
+ return pathlib.Path(path).absolute()
+
+
+def resolve_path(path: pathlib.Path):
+ s_path = str(path)
+ # Don't resolve if it's an absolute Windows path and we're not on Windows
+ # or if the path starts with a variable
+ if (os.name != 'nt' and s_path[1] == ':') or s_path.startswith('$'):
return path
- return os.path.abspath(path)
+ return path.resolve()
-def expandvars_plus(s):
- return os.path.expandvars(re.sub(r'\$\((.*)\)', r'${\1}', s))
+def expandvars_plus(s) -> pathlib.Path:
+ return pathlib.Path(os.path.expandvars(re.sub(r'\$\((.*)\)', r'${\1}', str(s))))
-class DotFfileParser:
+class SingleDotFfileParser:
- def __init__(self, filename):
+ def __init__(self, filename, options):
self.library_mapping = dict()
self.includes = set()
self.defines = []
- self.filename = ""
self.dotfdir = ""
- self.dotfname = ""
- self.csvfname = ""
- self.filecontent = []
+ self.file_content = []
self.linked_file_mapping = dict()
- self.filename = filename
- if not os.path.isfile(filename):
- print("*ERROR* File " + filename + " does not exist")
- sys.exit(1)
- if os.path.isabs(filename):
- filename = os.path.relpath(filename)
+ abort_if_false(pathlib.Path(filename).is_file(), f'*ERROR* File {filename} does not exist')
+ input_file = absolute_path(pathlib.Path(expandvars_plus(filename))).resolve()
+ self.dotfdir = input_file.parent
- self.dotfdir = os.path.dirname(filename)
- self.dotfname = os.path.basename(filename)
- self.csvfname = str(os.path.splitext(self.dotfname)[0]) + ".csv"
-
- self.filecontent = parse_dotf(filename)
+ self.file_content = parse_dotf(input_file)
parser_expect_library = False
parser_expect_dot_f = False
- newlib = 'work'
- for option in self.filecontent:
+
+ default_work_library = options.work_lib
+ new_library = default_work_library
+ for option in self.file_content:
if isinstance(option, list):
if option[0] == "+incdir":
- for fn in option[1:]:
- self.includes.add(rebase_file(fn[1:], self.dotfdir))
+ for include_folder in option[1:]:
+ while include_folder.startswith('+'):
+ include_folder = include_folder[1:]
+ include_folder_path = pathlib.Path(include_folder)
+ include_folder_path = expandvars_plus(include_folder_path)
+ if not is_absolute_path(include_folder_path):
+ # self.dotfdir is an absolute path
+ include_folder_path = self.dotfdir.joinpath(include_folder_path)
+ self.includes.add(resolve_path(include_folder_path))
elif option[0] == "+define":
for df in option[1:]:
self.defines.append(df[1:].strip())
else:
- print('Unknown multiline option (ignored) : ' + option[0])
+ print(f'*.f parse* Unknown multiline option (ignored) : {option[0]}')
else:
bare_option = str(option).strip('"')
if bare_option == "-makelib" or bare_option == "-work":
parser_expect_library = True
elif bare_option == "-endlib":
- newlib = 'work'
+ new_library = default_work_library
elif bare_option == "-f":
parser_expect_dot_f = True
elif bare_option.startswith("+") or bare_option.startswith("-"):
@@ -80,90 +92,85 @@ def __init__(self, filename):
elif parser_expect_dot_f:
parser_expect_dot_f = False
# Parse included .f file
- subfile = expandvars_plus(bare_option)
- if not os.path.isabs(subfile):
- subfile = os.path.join(self.dotfdir, subfile)
- subparser = DotFfileParser(subfile)
+ sub_file = expandvars_plus(bare_option)
+ if not is_absolute_path(sub_file):
+ sub_file = self.dotfdir.joinpath(sub_file)
+ subparser = SingleDotFfileParser(sub_file, options)
self.library_mapping.update(subparser.library_mapping)
self.includes |= subparser.includes
self.defines.extend(subparser.defines)
elif parser_expect_library:
# new library name
parser_expect_library = False
- newlib = bare_option.split('/')[-1]
+ new_library = bare_option.split('/')[-1]
else:
# Design file: add to library mapping
- if str(os.path.splitext(bare_option)[1]).lower() in ['.vhd', '.vhdl', '.v', '.sv']:
- self.add_to_library_mapping(bare_option, newlib)
+ design_file = pathlib.Path(bare_option)
+ if design_file.suffix.lower() in ['.vhd', '.vhdl', '.v', '.sv']:
+ self.add_to_library_mapping(design_file, new_library)
else:
print(f'*.f parse* skipping {bare_option}')
- def add_to_library_mapping(self, file, library):
- # For now, we'll return a dict of abs path => library
- # TODO Problem (to be re-solved): files may be mapped to more than one library, in which case this
- # approach won't work
- # Layout moves to ConverterHelper
-
- # We need to expand environment variables here, before expanding wildcards
- expanded_path = os.path.expandvars(file)
- if "*" in expanded_path:
- expanded_option = glob.glob(rebase_file(expanded_path, self.dotfdir), recursive=True)
- if not expanded_option:
- print(f'**warning** wildcard expression {expanded_option} does not match anything')
- self.library_mapping[abspath(rebase_file(expanded_path, self.dotfdir))] = library
- for f in expanded_option:
- self.library_mapping[abspath(f)] = library
+ def add_to_library_mapping(self, file: pathlib.Path, library):
+ # Note: we used to handle project layout ("standard in-place" and "simulator" layout) here
+ # Now we make the library mapping "just" a list of files and libraries, and we'll handle the project
+ # layout later.
+
+ # File paths in a .f file seem to be relative to the location of the .f file.
+ # Projects may contain multiple .f files in different locations.
+ # We make all paths absolute here. At a later stage, relative paths to the project root will be introduced
+ file = expandvars_plus(file)
+ if not is_absolute_path(file):
+ # self.dotfdir is an absolute path
+ file = self.dotfdir.joinpath(file)
+ if "*" in str(file):
+ expanded_file = glob.glob(str(file), recursive=True)
+ if not expanded_file:
+ print(f'*.f parse* **warning** wildcard expression {file} does not match anything, skipping')
+ return
+ for f in expanded_file:
+ self.add_file_to_library_mapping(pathlib.Path(f), library)
+ return
+ self.add_file_to_library_mapping(file, library)
+
+ def add_file_to_library_mapping(self, file: pathlib.Path, library):
+ file = resolve_path(file)
+ if file in self.library_mapping:
+ if not isinstance(self.library_mapping[file], list):
+ # Check against duplicates
+ if library != self.library_mapping[file]:
+ # Case: file mapped a second time
+ self.library_mapping[file] = [self.library_mapping[file], library]
+ else:
+ # Check against duplicates
+ if library not in self.library_mapping[file]:
+ # Case: file mapped a third time (or more)
+ self.library_mapping[file].append(library)
else:
- self.library_mapping[abspath(rebase_file(expanded_path, self.dotfdir))] = library
-
- # self.library_mapping[os.path.abspath(file)] = library
- #
- #
- #
- # if str(ArgsAndFileParser.get_layout_option()) == 'default':
- # if file in self.library_mapping:
- # file_base, file_ext = os.path.splitext(file)
- # newfile = file_base + '_' + library + file_ext
- # if newfile in self.library_mapping:
- # print('File already mapped to library: ' + file + ' => ' + library)
- # else:
- # self.library_mapping[newfile] = library
- # self.linked_file_mapping[newfile] = file
- # else:
- # self.library_mapping[file] = library
- # else:
- # # non-default library mapping
- # if library not in self.library_mapping:
- # self.library_mapping[library] = library
- # file_path, file_name = os.path.split(file)
- # self.linked_file_mapping[library + '/' + file_name] = file
-
-
-def parse_file(filename):
- parser = None
- if ',' in filename:
- filenames = filename.split(',')
- parser = DotFfileParser(filenames[0])
- for fn in filenames[1:]:
- subparser = DotFfileParser(fn)
- parser.library_mapping.update(subparser.library_mapping)
- parser.includes |= subparser.includes
- parser.defines.extend(subparser.defines)
- else:
- parser = DotFfileParser(filename)
-
- return parser
-
-
-usage = """usage: %prog [--layout=default|simulator] project-name dot-f-file [destination]
-
-destination is the current directory by default
-example: %prog MyProjectName filelist.f
-use a relative path to the .f file
-multiple .f files can be specified as a comma-separated list
-
-project layout: default : files are referenced in their current location.
- HDL files must reside in the destination folder or a sub-folder thereof.
- simulator: project consists of a virtual folder per library, into which HDL files are linked.
- Destination folder must be empty for 'simulator' project layout.
-"""
+ # General case: file mapped once
+ self.library_mapping[file] = library
+
+
+@project_file_parser('dotf')
+class DotFfileParser(ProjectFileParser):
+ """.f file"""
+ def __init__(self):
+ super().__init__()
+
+ def parse_file(self, filename, options):
+ library_mapping = dict()
+ verilog_includes = set()
+ verilog_defines = []
+
+ if isinstance(filename, list):
+ for this_file in filename:
+ parsed_result = self.parse_file(this_file, options)
+ library_mapping.update(parsed_result.library_mapping)
+ verilog_includes |= parsed_result.verilog_includes
+ verilog_defines.extend(parsed_result.verilog_defines)
+ else:
+ parser = SingleDotFfileParser(filename, options)
+ library_mapping = parser.library_mapping
+ verilog_includes = parser.includes
+ verilog_defines = parser.defines
+ return ProjectFileParserResult(library_mapping, verilog_includes, verilog_defines)
diff --git a/src/SigasiProjectCreator/DotF/parseFile.py b/src/SigasiProjectCreator/DotF/parseFile.py
index 35215a2..36dbfcf 100644
--- a/src/SigasiProjectCreator/DotF/parseFile.py
+++ b/src/SigasiProjectCreator/DotF/parseFile.py
@@ -51,7 +51,7 @@ def enterFilecont(self, ctx: DotFParser.FilecontContext):
def parse_dotf(filename):
- print('\nParsing file: ' + filename)
+ print(f'\nParsing file: {filename}')
input_stream = FileStream(filename)
lexer = DotFLexer(input_stream)
stream = CommonTokenStream(lexer)
diff --git a/src/SigasiProjectCreator/HdpProjectParser.py b/src/SigasiProjectCreator/HdpProjectParser.py
new file mode 100644
index 0000000..1ad4df4
--- /dev/null
+++ b/src/SigasiProjectCreator/HdpProjectParser.py
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+"""
+ :copyright: (c) 2008-2023 Sigasi
+ :license: BSD, see LICENSE for more details.
+"""
+from configparser import ConfigParser
+
+from SigasiProjectCreator.ProjectFileParser import ProjectFileParser, project_file_parser, ProjectFileParserResult
+
+
+@project_file_parser('hdp')
+class HdpParser(ProjectFileParser):
+ """HDP project"""
+ def __init__(self):
+ super().__init__()
+
+ def parse_file(self, hdp_file, options=None):
+ config = ConfigParser()
+ config.read(hdp_file)
+ entries = config.items("hdl")
+ library_mapping = {lib: path for path, lib in entries} # TODO HUH? isn't that the other way around?
+ return ProjectFileParserResult(library_mapping, None, None)
diff --git a/src/SigasiProjectCreator/ProjectCreator.py b/src/SigasiProjectCreator/ProjectCreator.py
new file mode 100644
index 0000000..9591d4c
--- /dev/null
+++ b/src/SigasiProjectCreator/ProjectCreator.py
@@ -0,0 +1,460 @@
+# -*- coding: utf-8 -*-
+"""
+ :copyright: (c) 2008-2023 Sigasi
+ :license: BSD, see LICENSE for more details.
+"""
+import os
+import pathlib
+
+from SigasiProjectCreator import abort_if_false
+from SigasiProjectCreator.ProjectFileParser import ProjectFileParser, get_parser_for_type, ProjectFileParserResult
+from SigasiProjectCreator.SigasiProject import SigasiProject
+from pathlib import Path
+
+
+project_creators = {}
+
+
+def project_creator(key):
+ def register(cls):
+ project_creators[key] = cls
+ return cls
+
+ return register
+
+
+# def running_in_cyg_win():
+# return platform.system().startswith("CYGWIN")
+
+
+# def convert_cygwin_path(cygwin_path):
+# cygwin_process = subprocess.Popen(['/usr/bin/cygpath', '--windows', cygwin_path], stdout=subprocess.PIPE)
+# cygwin_location = cygwin_process.communicate()[0].rstrip()
+# return posixpath(cygwin_location)
+
+class ProjectCreator:
+ def __init__(self, options):
+ self.options = options
+ self.virtual_folders = [pathlib.Path('Common Libraries')]
+ self.linked_paths_simulator_layout = []
+ self.project_root = pathlib.Path(options.destination_folder).absolute()
+
+ self.sigasi_project = SigasiProject(options)
+ self.sigasi_project.unmap("/")
+
+ def check_and_create_virtual_folder(self, file_name: pathlib.Path):
+ if not isinstance(file_name, pathlib.Path):
+ raise TypeError
+ filepath = file_name.parent
+ if filepath not in self.virtual_folders:
+ new_folders = []
+ while filepath and (str(filepath) != '.') and (filepath not in self.virtual_folders):
+ new_folders.insert(0, filepath)
+ filepath = filepath.parent
+ for new_path in new_folders:
+ self.virtual_folders.append(new_path)
+ self.sigasi_project.add_link(new_path, None, True)
+
+ def check_and_create_linked_folder(self, folder_name: pathlib.Path, folder_path: pathlib.Path):
+ if not (isinstance(folder_name, pathlib.Path) and isinstance(folder_path, pathlib.Path)):
+ raise TypeError
+ # TODO future work: map some folders into Common Libraries
+ # if folder_name.startswith('dependencies'):
+ # virtual_path_name = posixpath(os.path.join('Common Libraries', folder_name))
+ self.check_and_create_virtual_folder(folder_name)
+ self.sigasi_project.add_link(folder_name,
+ get_rel_or_abs_path(folder_path, self.project_root, self.options), True)
+
+ def parse_input_file(self) -> ProjectFileParserResult:
+ parser = get_parser_for_type(self.options.input_format)()
+ return parser.parse_file(self.options.input_file, self.options)
+
+ def create_project(self):
+ parser_output = self.parse_input_file()
+
+ verilog_includes = parser_output.verilog_includes
+ verilog_defines = parser_output.verilog_defines
+ entries = parser_output.library_mapping
+ if verilog_includes is not None and len(verilog_includes) > 0:
+ verilog_includes = [pathlib.Path(include_path) for include_path in verilog_includes]
+ if self.options.verbose:
+ print("Include folders: " + str(verilog_includes))
+ if (verilog_defines is not None) and (len(verilog_defines) > 0) and self.options.verbose:
+ print("Preprocessor definitions: " + str(verilog_defines))
+
+ new_entries = dict()
+ for path, library in entries.items():
+ new_entries[pathlib.Path(path)] = library
+ entries = new_entries
+ if self.options.verbose:
+ print("Library mapping: " + str(entries))
+
+ if not self.options.skip_check_exists:
+ for file in entries.keys():
+ abort_if_false(file.is_file(), f'*ERROR* file {file} does not exist')
+
+ (has_vhdl, has_verilog) = self.create_project_layout(entries)
+
+ # Update verilog includes
+ # Incoming are absolute paths
+ # If the path is a sub-path of the project folder, use the relative path
+ # If not:
+ # * make an `include_folders` folder
+ # * in it, make a link to the include folder, making sure to not have name clashes
+ # * use the project path
+ if verilog_includes is not None:
+ has_includes_folder = False
+ linked_include_folders = []
+ for include_folder in verilog_includes:
+ abort_if_false(self.options.skip_check_exists or include_folder.is_dir(),
+ f'*ERROR* include folder does not exist: {include_folder} ')
+ local_include_folder = None
+ if not include_folder.is_relative_to(self.project_root):
+ if not has_includes_folder:
+ self.sigasi_project.add_link('include_folders', None, True)
+ has_includes_folder = True
+ local_path = Path(include_folder.name)
+ local_path = get_unique_name(local_path, linked_include_folders)
+ linked_include_folders.append(local_path)
+ local_include_folder = Path('include_folders').joinpath(local_path)
+ self.sigasi_project.add_link(local_include_folder,
+ get_rel_or_abs_path(include_folder, self.project_root, self.options),
+ True)
+ else:
+ local_include_folder = pathlib.Path(os.path.relpath(include_folder, self.project_root))
+ self.sigasi_project.add_verilog_include(local_include_folder)
+
+ if self.options.uvm is not None:
+ self.sigasi_project.add_uvm(self.options.uvm, self.options.uvm_lib)
+
+ self.sigasi_project.set_languages(has_vhdl, has_verilog)
+ self.sigasi_project.write(self.project_root, None, verilog_defines, self.options.enable_vunit)
+
+ return self.sigasi_project, verilog_defines
+
+ def create_project_simulator_add_single(self, my_library, libraries, my_file):
+ if my_library not in libraries:
+ self.sigasi_project.add_link(my_library, None, True) # virtual folder named after the library
+ self.sigasi_project.add_mapping(my_library, my_library)
+ libraries.append(my_library)
+ linked_path = get_unique_name(pathlib.Path(my_library).joinpath(my_file.name),
+ self.linked_paths_simulator_layout)
+ self.linked_paths_simulator_layout.append(linked_path)
+ self.sigasi_project.add_link(linked_path, get_rel_or_abs_path(my_file, self.project_root, self.options), False)
+
+ def create_library_mapping_folders(self, entries, file_to_project_map):
+ # design_folders is a list of folders with actual design files in them
+ design_folders = get_design_folders(entries)
+ design_root = get_design_root_folder(design_folders)
+ for design_folder in design_folders:
+ folder_library = None
+ folder_list = os.listdir(design_folder)
+ for folder_item in folder_list:
+ # In each design folder = folder with design files:
+ # * Unmap all sub-folders. If a sub-folder contains design files, it will be handled later
+ # * Map this folder to the library of the first design file.
+ # * If any design files need to be mapped to a different library, do so on a file by file basis
+ # * If any design files need to not be mapped to a library, do so on a file by file basis
+ folder_item_with_path = design_folder.joinpath(folder_item)
+ if folder_item_with_path.is_dir():
+ local_folder = pathlib.Path(os.path.relpath(folder_item_with_path, design_root))
+ self.sigasi_project.unmap(local_folder)
+ elif folder_item_with_path.is_file() and folder_item_with_path.suffix in ['.vhd', '.vhdl', '.v', '.sv']:
+ file_with_path = design_folder.joinpath(folder_item)
+ file_with_path_relpath = pathlib.Path(os.path.relpath(file_with_path, design_root))
+ if file_with_path in entries:
+ my_lib = entries[file_with_path]
+ if isinstance(my_lib, list):
+ folder_library = self.map_file_to_multiple_libraries(file_with_path, my_lib, design_folder,
+ folder_library, design_root)
+ else:
+ if folder_library is None:
+ folder_library = self.map_folder_to_library(design_folder, my_lib, design_root)
+ elif folder_library != my_lib:
+ self.sigasi_project.add_mapping(file_with_path_relpath, my_lib)
+ elif self.options.layout != 'linked-files-tree':
+ self.sigasi_project.unmap(file_with_path_relpath)
+
+ def map_folder_to_library(self, design_folder, library, design_root):
+ # if parent folder is mapped to this library, clear the mapping of the current folder
+ parent_lib = self.sigasi_project.get_mapping(design_folder.parent)
+ design_folder_relpath = pathlib.Path(os.path.relpath(design_folder, design_root))
+ if parent_lib is None or parent_lib != library:
+ self.sigasi_project.add_mapping(design_folder_relpath, library)
+ else:
+ self.sigasi_project.remove_mapping(design_folder_relpath)
+ return library
+
+ def map_file_to_multiple_libraries(self, file_with_path, my_lib, design_folder, folder_library,
+ design_root):
+ file_is_mapped = (folder_library is not None) and (folder_library in my_lib)
+ for single_lib in my_lib:
+ if folder_library is None:
+ folder_library = self.map_folder_to_library(design_folder, single_lib, design_root)
+ file_is_mapped = True
+ elif single_lib != folder_library:
+ file_with_path_relpath = pathlib.Path(os.path.relpath(file_with_path, design_root))
+ if file_is_mapped:
+ new_file = file_with_path_relpath.parent.joinpath(
+ f'{file_with_path_relpath.stem}_{single_lib}'
+ f'{file_with_path_relpath.suffix}')
+ self.sigasi_project.add_link(new_file,
+ get_rel_or_abs_path(file_with_path,
+ self.project_root,
+ self.options))
+ self.sigasi_project.add_mapping(new_file, single_lib)
+ else:
+ self.sigasi_project.add_mapping(file_with_path_relpath, single_lib)
+ file_is_mapped = True
+ return folder_library
+
+ def create_library_mapping_per_file(self, mapping_entries, filesystem_to_project_mapping):
+ for item, library in mapping_entries.items():
+ self.add_library_mapping(filesystem_to_project_mapping[item], library, item)
+
+ def add_library_mapping(self, project_file: pathlib.Path, libraries, filesystem_file):
+ if isinstance(libraries, list):
+ first_library = True
+ for library in libraries:
+ if first_library:
+ self.sigasi_project.add_mapping(project_file, library)
+ first_library = False
+ else:
+ new_file = project_file.parent.joinpath(f'{project_file.stem}_{library}{project_file.suffix}')
+ self.sigasi_project.add_link(new_file,
+ get_rel_or_abs_path(filesystem_file, self.project_root, self.options))
+ self.sigasi_project.add_mapping(new_file, library)
+ else:
+ self.sigasi_project.add_mapping(project_file, libraries)
+
+
+@project_creator('in-place')
+class ProjectCreatorInPlace(ProjectCreator):
+ """default"""
+
+ def __init__(self, options):
+ super().__init__(options)
+
+ def create_project_layout(self, entries):
+ # In place means that we assume that the design files are in the "destination" tree.
+ # TODO future work: handle files not in the destination tree: link in some way (out of scope of ticket #23)
+ mapping_style = self.options.mapping
+ map_folders = (mapping_style == 'folder')
+ destination_folder = self.options.destination_folder
+
+ has_vhdl = False
+ has_verilog = False
+ for my_file, my_library in entries.items():
+ if not my_file.is_relative_to(destination_folder):
+ raise ValueError(f'*In-place layout* file {my_file} is not in destination folder {destination_folder}')
+ file_ext = my_file.suffix.lower()
+ if file_ext in ['.vhd', '.vhdl']:
+ has_vhdl = True
+ elif file_ext in ['.v', '.sv']:
+ has_verilog = True
+ local_file = my_file.relative_to(destination_folder)
+ if not map_folders:
+ self.add_library_mapping(local_file, my_library, local_file)
+
+ if map_folders:
+ self.create_library_mapping_folders(entries, None)
+
+ return has_vhdl, has_verilog
+
+
+@project_creator('simulator')
+class ProjectCreatorSimulator(ProjectCreator):
+ """one folder per library with linked files"""
+
+ def __init__(self, options):
+ super().__init__(options)
+
+ def create_project_layout(self, entries):
+ # In this layout, the project contains one virtual folder per HDL library, which in turn contains
+ # links to each relevant file. Virtual folders are mapped to libraries.
+ libraries = []
+ has_vhdl = False
+ has_verilog = False
+ for my_file, my_library in entries.items():
+ file_ext = my_file.suffix.lower()
+ if file_ext in ['.vhd', '.vhdl']:
+ has_vhdl = True
+ elif file_ext in ['.v', '.sv']:
+ has_verilog = True
+ ref_path = None
+ if isinstance(my_library, list):
+ for my_lib in my_library:
+ self.create_project_simulator_add_single(my_lib, libraries, my_file)
+ else:
+ self.create_project_simulator_add_single(my_library, libraries, my_file)
+ return has_vhdl, has_verilog
+
+
+@project_creator('linked-files-flat')
+class ProjectCreatorLinkedFilesFlat(ProjectCreator):
+ """one folder with links to all files"""
+
+ def __init__(self, options):
+ super().__init__(options)
+
+ def create_project_layout(self, entries):
+ has_vhdl = False
+ has_verilog = False
+ linked_paths = []
+ for path, library in entries.items():
+ abort_if_false(not pathlib.Path(path).is_relative_to(self.project_root),
+ f'*ERROR* linked project: destination folder {self.project_root} may not contain design file {path}')
+ file_ext = path.suffix.lower()
+ if file_ext in ['.vhd', '.vhdl']:
+ has_vhdl = True
+ elif file_ext in ['.v', '.sv']:
+ has_verilog = True
+ if isinstance(library, list):
+ for my_library in library:
+ linked_path = get_unique_name(pathlib.Path(path.name), linked_paths)
+ linked_paths.append(linked_path)
+ self.sigasi_project.add_link(linked_path,
+ get_rel_or_abs_path(path, self.project_root, self.options), False)
+ self.sigasi_project.add_mapping(linked_path, my_library)
+ else:
+ linked_path = get_unique_name(pathlib.Path(path.name), linked_paths)
+ linked_paths.append(linked_path)
+ self.sigasi_project.add_link(linked_path,
+ get_rel_or_abs_path(path, self.project_root, self.options), False)
+ self.sigasi_project.add_mapping(linked_path, library)
+ return has_vhdl, has_verilog
+
+
+@project_creator('linked-files-tree')
+class ProjectCreatorLinkedFilesTree(ProjectCreator):
+ """virtual folders like the source tree, with links to files"""
+
+ def __init__(self, options):
+ super().__init__(options)
+
+ def create_project_layout(self, entries):
+ has_vhdl = False
+ has_verilog = False
+
+ design_folders = get_design_folders(entries)
+ design_root = get_design_root_folder(design_folders)
+ abs_to_rel_file = {}
+
+ for path, library in entries.items():
+ abort_if_false(not pathlib.Path(path).is_relative_to(self.project_root),
+ f'*ERROR* linked project: destination folder {self.project_root} may not contain design file {path}')
+ file_ext = path.suffix.lower()
+ if file_ext in ['.vhd', '.vhdl']:
+ has_vhdl = True
+ elif file_ext in ['.v', '.sv']:
+ has_verilog = True
+
+ rel_path = path.relative_to(design_root)
+ self.check_and_create_virtual_folder(rel_path)
+ self.sigasi_project.add_link(rel_path, get_rel_or_abs_path(path, self.project_root, self.options), False)
+ abs_to_rel_file[path] = rel_path
+
+ if self.options.mapping == 'file':
+ self.create_library_mapping_per_file(entries, abs_to_rel_file)
+ else:
+ self.create_library_mapping_folders(entries, abs_to_rel_file)
+
+ return has_vhdl, has_verilog
+
+
+@project_creator('linked-folders')
+class ProjectCreatorLinkedFolders(ProjectCreator):
+ """mix of virtual and linked folders"""
+
+ def __init__(self, options):
+ # super(ProjectCreatorLinkedFolders, self).__init__(options)
+ super().__init__(options)
+
+ def create_project_layout(self, entries):
+ has_vhdl = False
+ has_verilog = False
+
+ # design_folders is a list of folders with actual design files
+ design_folders = get_design_folders(entries)
+ design_root = get_design_root_folder(design_folders)
+ design_subtrees = get_design_subtrees(design_folders)
+ for subtree in design_subtrees:
+ self.check_and_create_linked_folder(pathlib.Path(os.path.relpath(subtree, design_root)), subtree)
+
+ abs_to_rel_file = {}
+ for path, library in entries.items():
+ abort_if_false(not path.is_relative_to(self.project_root),
+ f'*ERROR* linked project: destination folder {self.project_root} may not contain design file {path}')
+ file_ext = path.suffix.lower()
+ if file_ext in ['.vhd', '.vhdl']:
+ has_vhdl = True
+ elif file_ext in ['.v', '.sv']:
+ has_verilog = True
+ # abs_to_rel_file[path] = pathlib.Path(os.path.relpath(path))
+ for subtree in design_subtrees:
+ if path.is_relative_to(subtree):
+ abs_to_rel_file[path] = path.relative_to(subtree.parent)
+
+ if self.options.mapping == 'file':
+ self.create_library_mapping_per_file(entries, abs_to_rel_file)
+ else:
+ self.create_library_mapping_folders(entries, abs_to_rel_file)
+
+ return has_vhdl, has_verilog
+
+
+def get_project_creator(options):
+ abort_if_false(options.layout in project_creators.keys(), f'Invalid layout option: {options.layout}')
+ return project_creators[options.layout](options)
+
+
+def get_unique_name(path: pathlib.Path, existing_path_list):
+ if (not existing_path_list) or (path not in existing_path_list):
+ return path
+ seq = 1
+ new_path = path
+ path_base = path.parent.joinpath(path.stem)
+ path_ext = path.suffix
+ while new_path in existing_path_list and seq < 1000:
+ new_path = Path(f'{path_base}_{seq}{path_ext}')
+ seq += 1
+ abort_if_false(new_path not in existing_path_list, f'*ERROR* Cannot find a unique name for {path}')
+ return new_path
+
+
+def get_design_folders(entries) -> list[pathlib.Path]:
+ folders = []
+ for path, library in entries.items():
+ folder = path.parent
+ if folder not in folders:
+ folders.append(folder)
+ folders.sort()
+ return folders
+
+
+def get_design_root_folder(folder_list) -> pathlib.Path:
+ return pathlib.Path(os.path.commonpath(folder_list))
+
+
+def get_design_subtrees(folder_list):
+ # Design subtrees are folders which contain design files, while none of their parent folders contain design files
+ folder_list.sort()
+ design_root_folders = []
+ current_folder = None
+ for my_folder in folder_list:
+ if (current_folder is None) or (not my_folder.is_relative_to(current_folder)):
+ design_root_folders.append(my_folder)
+ current_folder = my_folder
+ return design_root_folders
+
+
+def get_rel_or_abs_path(my_path: pathlib.Path, project_root, options):
+ # If a relative path is given at this point, it is returned unchanged.
+ if not my_path.is_absolute():
+ return my_path
+ # If an absolute path is given and a relative path is expected, the relative path is returned.
+ destination_path = pathlib.Path(project_root).absolute()
+ if my_path.is_relative_to(destination_path) or options.use_relative_path(my_path):
+ # return input_path.relative_to(destination_path)
+ return Path(os.path.relpath(my_path, project_root))
+ return my_path.absolute()
diff --git a/src/SigasiProjectCreator/ProjectFileParser.py b/src/SigasiProjectCreator/ProjectFileParser.py
new file mode 100644
index 0000000..cb2b323
--- /dev/null
+++ b/src/SigasiProjectCreator/ProjectFileParser.py
@@ -0,0 +1,40 @@
+import pathlib
+
+from SigasiProjectCreator import abort_if_false
+from dataclasses import dataclass
+
+project_file_parsers = {}
+
+
+@dataclass
+class ProjectFileParserResult:
+ library_mapping: dict[pathlib.Path, str]
+ verilog_includes: set[str]
+ verilog_defines: list[str]
+
+
+def project_file_parser(key):
+ def register(cls):
+ project_file_parsers[key] = cls
+ return cls
+
+ return register
+
+
+@project_file_parser('filelist')
+class ProjectFileParser:
+ """file list"""
+
+ def __init__(self):
+ pass
+
+ def parse_file(self, filename, options):
+ # Default parser is no parser: the filename(s) are the HDL files
+ library_mapping = {pathlib.Path(entry).absolute().resolve(): options.worklib
+ for entry in filename}
+ return ProjectFileParserResult(library_mapping, None, None)
+
+
+def get_parser_for_type(input_type) -> ProjectFileParser:
+ abort_if_false(input_type in project_file_parsers.keys(), f'Invalid input type: {input_type}')
+ return project_file_parsers[input_type]
diff --git a/src/SigasiProjectCreator/ProjectOptions.py b/src/SigasiProjectCreator/ProjectOptions.py
new file mode 100644
index 0000000..328f30a
--- /dev/null
+++ b/src/SigasiProjectCreator/ProjectOptions.py
@@ -0,0 +1,151 @@
+# -*- coding: utf-8 -*-
+"""
+ :copyright: (c) 2008-2023 Sigasi
+ :license: BSD, see LICENSE for more details.
+"""
+import argparse
+import pathlib
+
+from SigasiProjectCreator import VerilogVersion, VhdlVersion, ProjectCreator, ProjectFileParser
+
+
+class ProjectOptions:
+ def __init__(self, args_list=None):
+ parser = argparse.ArgumentParser(prog='SigasiProjectCreator')
+ parser.add_argument('project_name', help='Project name')
+ parser.add_argument('input_file', help='Input file or comma-separated list of input files', nargs='+')
+ parser.add_argument('-d', '--destination', action='store', dest='destination_folder',
+ help='Root folder of created project', type=pathlib.Path, default=pathlib.Path.cwd())
+ parser.add_argument('-l', '--layout', choices=ProjectCreator.project_creators.keys(), default='in-place',
+ help=('Any of the following layouts: ' + ', '.join(
+ f'{key} ({cls.__doc__})' for key, cls in ProjectCreator.project_creators.items())))
+ parser.add_argument('--uvm', help='Add UVM to the project, using UVM from the given install path',
+ dest='uvm', type=pathlib.Path)
+ parser.add_argument('--use-uvm-home', help='Add UVM to the project. Sigasi Studio will use the UVM_HOME '
+ 'environment variable to find your UVM installation',
+ dest='uvmhome', action='store_true')
+ parser.add_argument('--uvmlib', help='Library in which to compile the UVM package (default: the library '
+ 'set with `--work`, or `work`)',
+ dest='uvmlib', default=None)
+ parser.add_argument('--format', action='store', dest='format',
+ choices=ProjectFileParser.project_file_parsers.keys(), default=None,
+ help='Force input format (ignore file extension): ' + ', '.join(
+ f'{key} ({cls.__doc__})' for key, cls in ProjectFileParser.project_file_parsers.items()))
+ parser.add_argument('--mapping', action='store', dest='mapping',
+ choices=['file', 'folder'], default='file',
+ help='Library mapping style: `folder` = map folders where possible, `file` = map '
+ 'individual files (default). Option `folder` requires that files are actually '
+ 'available. Only relevant with `default`, `linked-files-tree` and '
+ '`linked-folders` project layouts')
+ parser.add_argument('--enable-vhdl', action='store_true', dest='enable_vhdl',
+ help='Force VHDL support (regardless of VHDL file presence)')
+ parser.add_argument('--vhdl-version', action='store', dest='vhdl_version',
+ choices=VhdlVersion.get_str_enums(), default=str(VhdlVersion.TWENTY_O_EIGHT),
+ help='Set VHDL version (default VHDL-2008)')
+ parser.add_argument('--enable-verilog', action='store_true', dest='enable_verilog',
+ help='Force (System)Verilog support (regardless of (System)Verilog file presence)')
+ parser.add_argument('--verilog-as-sv', action='store_true', dest='system_verilog',
+ help='Treat .v files as SystemVerilog')
+ parser.add_argument('--enable-vunit', action='store_true', dest='enable_vunit',
+ help='Enable VUnit support')
+ parser.add_argument('-w', '--work', help='Main HDL library name (default `work`)',
+ dest='worklib', default='work')
+ parser.add_argument('--skip-check-exists', action='store_true', dest='skip_check_exists',
+ help='Skip checking whether files and folders exist')
+ parser.add_argument('--encoding', action='store', dest='encoding',
+ default='UTF-8', help='Set unicode character encoding (default: UTF-8)')
+ parser.add_argument('-f', '--force', action='store_true', dest='force_write',
+ help='Overwrite existing project files')
+ parser.add_argument('--rel-path', action='store', dest='rel_path_root',
+ nargs='*', type=pathlib.Path,
+ help='Use relative paths for links to files in this folder and its sub-folders')
+ parser.add_argument('-v', '--verbose', action='store_true', dest='verbose',
+ help='Verbose output')
+
+ # Run the command line parser
+ args = parser.parse_args(args_list)
+
+ # Transfer parsed arguments to attributes
+ self.project_name = args.project_name
+ self.input_file = args.input_file
+ self.input_format = args.format
+
+ for infile in self.input_file:
+ if not pathlib.Path(infile).is_file():
+ parser.exit(1, f'Input file \'{infile}\' does not exist or is not a file\n')
+ if args.format is None:
+ # Only check the file type if it's not overridden
+ if self.input_format is None:
+ self.input_format = get_file_type(infile)
+ else:
+ if self.input_format != get_file_type(infile):
+ parser.error('Mixed input file types are not supported')
+ if len(self.input_file) == 1:
+ self.input_file = self.input_file[0]
+
+ if args.destination_folder.exists():
+ if not args.destination_folder.is_dir():
+ parser.exit(1, f'Cannot create project folder {args.destination_folder}: a file with that name '
+ f'exists\n')
+ else:
+ if not args.destination_folder.parent.is_dir():
+ parser.exit(1, f'Cannot create project folder {args.destination_folder.name} in '
+ f'{args.destination_folder.parent}\n')
+ args.destination_folder.mkdir()
+ self.destination_folder = args.destination_folder.absolute().resolve()
+
+ self.uvm = None
+ if args.uvmhome:
+ if args.uvm is not None:
+ parser.error('Conflicting options --uvm and --use-uvm-home used')
+ self.uvm = pathlib.Path('ENV-UVM_HOME')
+ elif args.uvm is not None:
+ uvm_path = pathlib.Path(args.uvm)
+ if not uvm_path.is_dir():
+ parser.exit(1, f'UVM home \'{args.uvm}\' must be a folder\n')
+ if not (uvm_path.joinpath('src/uvm_macros.svh').is_file()
+ and uvm_path.joinpath('src/uvm_pkg.sv').is_file()):
+ parser.exit(1, f'UVM folder \'{args.uvm}/src\' must contain uvm_macros.svh and uvm_pkg.sv\n')
+ self.uvm = uvm_path
+
+ if args.uvmlib is None:
+ self.uvm_lib = args.worklib
+ else:
+ self.uvm_lib = args.uvmlib
+
+ self.rel_path_root = None
+ if args.rel_path_root:
+ self.rel_path_root = [pathlib.Path(folder).absolute().resolve() for folder in args.rel_path_root]
+
+ self.layout = args.layout
+ self.mapping = args.mapping
+ self.enable_vhdl = args.enable_vhdl
+ self.enable_verilog = args.enable_verilog
+ self.enable_vunit = args.enable_vunit
+ self.work_lib = args.worklib
+ self.encoding = args.encoding
+ self.vhdl_version = int(args.vhdl_version)
+ self.verilog_version = VerilogVersion.TWENTY_TWELVE if args.system_verilog else VerilogVersion.TWENTY_O_FIVE
+ self.force_overwrite = args.force_write
+ self.skip_check_exists = args.skip_check_exists
+ self.verbose = args.verbose
+
+ def use_relative_path(self, my_path):
+ # TODO figure out path/purepath mess (windows related??)
+ pure_path = pathlib.PurePath(pathlib.Path(my_path).absolute())
+ if self.rel_path_root:
+ for path_root in self.rel_path_root:
+ if pure_path.is_relative_to(path_root):
+ return True
+ return False
+
+
+def get_file_type(filename):
+ file_ext = str(pathlib.Path(filename).suffix).lower()
+ if file_ext.startswith('.'):
+ file_ext = file_ext[1:]
+ if file_ext == 'f':
+ return 'dotf'
+ if file_ext in ['csv', 'hdp']:
+ return file_ext
+ return 'filelist'
diff --git a/src/SigasiProjectCreator/SettingsFileWriter.py b/src/SigasiProjectCreator/SettingsFileWriter.py
index 0ce0e01..e727552 100644
--- a/src/SigasiProjectCreator/SettingsFileWriter.py
+++ b/src/SigasiProjectCreator/SettingsFileWriter.py
@@ -1,7 +1,12 @@
-import os
+import pathlib
+from SigasiProjectCreator import abort_if_false
-def write(destination, name, content):
- library_mapping_file = os.path.abspath(os.path.join(destination, name))
- with open(library_mapping_file, "wb") as f:
+
+def write(destination, name, content, force_overwrite):
+ settings_file = pathlib.Path(destination).joinpath(name)
+ abort_if_false((force_overwrite or not settings_file.exists()),
+ f'*ERROR* project file {settings_file} exists, ' \
+ 'won\'t overwrite (use `-f` or `--force` to overwrite)')
+ with open(settings_file, "wb") as f:
f.write(content.encode())
diff --git a/src/SigasiProjectCreator/Creator.py b/src/SigasiProjectCreator/SigasiProject.py
similarity index 57%
rename from src/SigasiProjectCreator/Creator.py
rename to src/SigasiProjectCreator/SigasiProject.py
index 1693010..6b042b9 100644
--- a/src/SigasiProjectCreator/Creator.py
+++ b/src/SigasiProjectCreator/SigasiProject.py
@@ -3,12 +3,10 @@
:copyright: (c) 2008-2023 Sigasi
:license: BSD, see LICENSE for more details.
"""
-import os
-import re
import pathlib
from string import Template
-from SigasiProjectCreator import absnormpath, posixpath
+from SigasiProjectCreator import posixpath, abort_if_false
from SigasiProjectCreator import VhdlVersion
from SigasiProjectCreator import VerilogVersion
from SigasiProjectCreator import SettingsFileWriter
@@ -32,6 +30,22 @@ def check_hdl_versions(vhdl_version, verilog_version):
raise ValueError("\n".join(filter(None, [vhdl_error, verilog_error])))
+def get_settings_folder(destination: pathlib.Path, suffix=None):
+ if suffix:
+ settings_folder = destination.joinpath(suffix)
+ else:
+ settings_folder = destination
+ if settings_folder.exists():
+ abort_if_false(settings_folder.is_dir(), f'*ERROR* Settings folder {settings_folder} ' \
+ 'exists but is not a folder')
+ return settings_folder
+ abort_if_false(settings_folder.parent.is_dir(),
+ f'*ERROR* Cannot create settings folder {settings_folder}, parent is not' \
+ 'an existing folder')
+ settings_folder.mkdir()
+ return settings_folder
+
+
class LibraryMappingFileCreator:
"""A Library Mapping File Creator helps you to easily create a Sigasi Library Mapping file.
@@ -57,7 +71,6 @@ class LibraryMappingFileCreator:
__MAPPING_TEMPLATE = Template(' \n')
__DEFAULT_VERILOG_MAPPINGS = {
- "": "not mapped"
}
__DEFAULT_VHDL_MAPPINGS = {
@@ -65,44 +78,57 @@ class LibraryMappingFileCreator:
"Common Libraries/IEEE Synopsys": "ieee",
"Common Libraries": "not mapped",
"Common Libraries/STD": "std",
- "": "not mapped"
}
- def __init__(self, vhdl_version=VhdlVersion.NINETY_THREE, verilog_version=None):
+ def __init__(self):
self.__entries = dict()
- self.__add_default_mappings()
+ self.__vhdl_version = None
+ self.__verilog_version = None
- check_hdl_versions(vhdl_version, verilog_version)
+ def set_languages(self, vhdl_version, verilog_version):
self.__vhdl_version = vhdl_version
self.__verilog_version = verilog_version
+ self.__add_default_mappings()
def __add_default_mappings(self):
- if VhdlVersion is not None:
+ # Default value
+ self.add_mapping("", "not mapped")
+ if self.__vhdl_version is not None:
for path, library in self.__DEFAULT_VHDL_MAPPINGS.items():
self.add_mapping(path, library)
- if VerilogVersion is not None:
+ if self.__verilog_version is not None:
for path, library in self.__DEFAULT_VERILOG_MAPPINGS.items():
self.add_mapping(path, library)
- if VhdlVersion is None and VerilogVersion is None:
- # Default value
- self.add_mapping("", "not mapped")
def __str__(self):
mappings = ""
for (path, library) in sorted(self.__entries.items()):
mappings += self.__MAPPING_TEMPLATE.substitute(
- path=path,
- library=library)
+ path=path,
+ library=library)
return self.__LIBRARIES_TEMPLATE.substitute(mappings=mappings)
- def add_mapping(self, path, library):
+ def add_mapping(self, path, library=None):
+ if library is None:
+ self.__entries[path] = 'not mapped'
self.__entries[path] = library
+ def get_mapping(self, path):
+ result = None
+ if path in self.__entries:
+ result = self.__entries[path]
+ if result == 'not mapped':
+ result = None
+ return result
+
def unmap(self, path):
self.__entries[path] = "not mapped"
- def write(self, destination):
- SettingsFileWriter.write(destination, ".library_mapping.xml", str(self))
+ def remove_mapping(self, path):
+ del self.__entries[path]
+
+ def write(self, destination, force_overwrite):
+ SettingsFileWriter.write(destination, ".library_mapping.xml", str(self), force_overwrite)
class ProjectFileCreator:
@@ -121,7 +147,7 @@ class ProjectFileCreator:
"""
__LINK_TEMPLATE = Template(
-'''\t\t
+ '''\t\t
\t\t\t${name}
\t\t\t${link_type}
\t\t\t<${loc_type}>${location}${loc_type}>
@@ -140,7 +166,7 @@ class ProjectFileCreator:
\t\t\n'''
__PROJECT_FILE_TEMPLATE = Template(
-'''
+ '''
\t${project_name}
\t
@@ -168,34 +194,19 @@ class ProjectFileCreator:
["Common Libraries/STD", Template("sigasiresource:/vhdl/${version}/STD")],
]
- force_vhdl = None
- force_verilog = None
- force_vunit = None
-
- def __init__(self, project_name, vhdl_version=VhdlVersion.NINETY_THREE, verilog_version=None):
- check_hdl_versions(vhdl_version, verilog_version)
+ def __init__(self, project_name):
self.__project_name = project_name
- self.__version = vhdl_version
self.__links = []
self.__project_references = []
- self.__add_default_links()
-
- def is_verilog(self):
- # Workaround for VHDL/Verilog/mixed detection, see below
- if self.force_verilog is not None:
- return self.force_verilog
- # TODO you can't check for a Verilog nature like this, files in the library mapping are ignored
- vl_ext = re.compile(r"\.sv[hi]?$|\.v[h]?$", re.IGNORECASE)
- return any([vl_ext.search(l[1]) for l in self.__links])
-
- def is_vhdl(self):
- # Workaround for VHDL/Verilog/mixed detection, see below
- if self.force_vhdl is not None:
- return self.force_vhdl
- vhdl_ext = re.compile(r"\.vhd[l]?$", re.IGNORECASE)
- # VHDL is the default
- # TODO you can't check for a Mixed VHDL/Verilog nature like this, files in the library mapping are ignored
- return not self.is_verilog() or any([vhdl_ext.search(l[1]) for l in self.__links])
+ self.vhdl_version = None
+ self.verilog_version = None
+ self.force_vunit = None
+
+ def set_languages(self, vhdl_version, verilog_version):
+ self.vhdl_version = vhdl_version
+ self.verilog_version = verilog_version
+ if vhdl_version is not None:
+ self.__add_default_links()
def is_vunit(self):
if self.force_vunit is not None:
@@ -204,26 +215,25 @@ def is_vunit(self):
def __add_default_links(self):
for name, template in self.__DEFAULT_LINKS:
- self.__links.append([name, template.substitute(version=self.__version), True, False])
+ self.__links.append([name, template.substitute(version=self.vhdl_version), True, False])
def __str__(self):
links = ""
project_references = ""
buildspecs = ""
natures = ""
- # TODO git rid of VHDL common libraries for non-VHDL projects
for [name, location, folder, is_path] in self.__links:
location_type = "location" if (is_path and not str(location).startswith('virtual')) else "locationURI"
links += self.__LINK_TEMPLATE.substitute(
- name=name,
- link_type=2 if folder else 1,
- loc_type=location_type,
- location=location)
+ name=name,
+ link_type=2 if folder else 1,
+ loc_type=location_type,
+ location=location)
- if self.is_verilog():
+ if self.verilog_version is not None:
natures += self.__VERILOG_NATURE
- if self.is_vhdl():
+ if self.vhdl_version is not None:
natures += self.__VHDL_NATURE
if self.is_vunit():
@@ -243,18 +253,19 @@ def __str__(self):
)
def add_link(self, name, location, folder=False):
- if name.startswith(".."):
- raise ValueError('invalid name "' + name + '", a name can not start with dots')
- self.__links.append([name, location, folder, True])
+ if str(location).startswith('virtual'):
+ self.__links.append([name, location, folder, False])
+ else:
+ # if name.startswith(".."):
+ # raise ValueError('invalid name "' + name + '", a name can not start with dots')
+ self.__links.append([name, project_location_path(location), folder, True])
def add_project_reference(self, name):
self.__project_references.append(name)
- def write(self, destination, force_vhdl=None, force_verilog=None, force_vunit=None):
- self.force_vhdl = force_vhdl
- self.force_verilog = force_verilog
- self.force_vunit = force_vunit
- SettingsFileWriter.write(destination, ".project", str(self))
+ def write(self, destination, force_vunit, force_overwrite):
+ self.force_vunit = force_vunit
+ SettingsFileWriter.write(destination, ".project", str(self), force_overwrite)
class ProjectVersionCreator:
@@ -273,21 +284,27 @@ def __init__(self, version=VhdlVersion.NINETY_THREE):
self.version = version
self.lang = "vhdl" if self.version in VhdlVersion.get_enums() else "verilog"
- def write(self, destination):
- self.write_version(destination)
+ def write(self, destination, force_overwrite):
+ self.write_version(destination, force_overwrite)
+
+ def get_vhdl_version(self):
+ if self.lang == 'vhdl':
+ return self.version
+ return None
+
+ def get_verilog_version(self):
+ if self.lang == 'verilog':
+ return self.version
+ return None
def __str__(self):
return "={0}".format(self.version)
- def write_version(self, destination):
- settings_dir = os.path.join(destination, ".settings")
- # Create .settings dir if it doesn't yet exist
- if not os.path.exists(settings_dir):
- os.makedirs(settings_dir)
+ def write_version(self, destination, force_overwrite):
+ settings_dir = get_settings_folder(destination, '.settings')
version_file_path = "com.sigasi.hdt.{0}.version.prefs".format(self.lang)
- version_file = os.path.join(settings_dir, version_file_path)
- if self.version is not None and not os.path.exists(version_file):
- SettingsFileWriter.write(settings_dir, version_file_path, str(self))
+ if self.version is not None:
+ SettingsFileWriter.write(settings_dir, version_file_path, str(self), force_overwrite)
class ProjectPreferencesCreator:
@@ -297,75 +314,74 @@ class ProjectPreferencesCreator:
Limitation: only Verilog supported atm
"""
+
def __init__(self, language, verilog_includes, verilog_defines):
self.verilog_includes = verilog_includes
- self.verilog_defines = verilog_defines
+ self.verilog_defines = verilog_defines
self.lang = language
- def write(self, destination):
- settings_dir = os.path.join(destination, ".settings")
- # Create .settings dir if it doesn't yet exist
- if not os.path.exists(settings_dir):
- os.makedirs(settings_dir)
+ def write(self, destination, force_overwrite):
+ settings_dir = get_settings_folder(destination, '.settings')
prefs_file_path = "com.sigasi.hdt.{0}.{1}.prefs".format(self.lang, str(self.lang).title())
- prefs_file = os.path.join(settings_dir, prefs_file_path)
- # TODO why not overwrite?
- if not os.path.exists(prefs_file):
- rel_verilog_includes = []
- abs_destination = absnormpath(destination)
- # TODO improve PATH handling
- for path in self.verilog_includes:
- if str(path).startswith('Common Libraries'):
- rel_verilog_includes.append(path)
- else:
- # TODO why is this line here? # abs_path = absnormpath(path)
- relative_path = os.path.relpath(path, abs_destination)
- rel_verilog_includes.append(posixpath(relative_path))
- self.verilog_includes = rel_verilog_includes
- SettingsFileWriter.write(settings_dir, prefs_file_path, str(self))
+ SettingsFileWriter.write(settings_dir, prefs_file_path, str(self), force_overwrite)
def __str__(self):
- incstr = ""
- defstr = ""
+ includes_string = ""
+ defines_string = ""
if self.lang == 'verilog' and self.verilog_includes is not None and len(self.verilog_includes) > 0:
if isinstance(self.verilog_includes, list) and list:
- incstr = "includePath="
+ includes_string = "includePath="
first = True
- for incfile in self.verilog_includes:
+ for include_folder in self.verilog_includes:
if not first:
- incstr += ";"
+ includes_string += ";"
first = False
- incstr += incfile
- incstr += "\n"
+ includes_string += posixpath(include_folder)
+ includes_string += "\n"
if self.lang == 'verilog' and self.verilog_defines is not None and len(self.verilog_defines) > 0:
- defstr = "propertiesDefine="
+ defines_string = "propertiesDefine="
for definition in self.verilog_defines:
- defstr += "`define " + definition.replace('=',' ') + "\\r\\n"
- defstr += "\n"
- return "eclipse.preferences.version=1\n" + incstr + defstr
+ defines_string += "`define " + definition.replace('=', ' ') + "\\r\\n"
+ defines_string += "\n"
+ return "eclipse.preferences.version=1\n" + includes_string + defines_string
+
+
+class ProjectEncodingCreator:
+ """
+ Create /.settings/com.sigasi.hdt.vhdl.version.prefs
+ with file encoding settings (default UTF-8)
+ """
+
+ def __init__(self, encoding='UTF-8'):
+ self.encoding = encoding
+
+ def write(self, destination, force_overwrite):
+ settings_dir = get_settings_folder(destination, '.settings')
+ prefs_file_path = "org.eclipse.core.resources.prefs"
+ SettingsFileWriter.write(settings_dir, prefs_file_path, str(self), force_overwrite)
+
+ def __str__(self):
+ return f'eclipse.preferences.version=1\nencoding/={self.encoding}\n'
+
class VUnitPreferencesCreator:
""" Help to write a .settings file for the VUnit script (run.py) location
"""
- def __init__(self, VUnitScript="run.py"):
- self.script = VUnitScript
-
- def write(self, destination):
- settings_dir = os.path.join(destination, ".settings")
- # Create .settings dir if it doesn't yet exist
- if not os.path.exists(settings_dir):
- os.makedirs(settings_dir)
+
+ def __init__(self, vunit_script="run.py"):
+ self.script = vunit_script
+
+ def write(self, destination, force_overwrite):
+ settings_dir = get_settings_folder(destination, '.settings')
prefs_file_path = "com.sigasi.hdt.toolchains.vunit.prefs"
- prefs_file = os.path.join(settings_dir, prefs_file_path)
- if not os.path.exists(prefs_file):
- SettingsFileWriter.write(settings_dir, prefs_file_path, str(self))
-
+ SettingsFileWriter.write(settings_dir, prefs_file_path, str(self), force_overwrite)
+
def __str__(self):
- scriptsstr = "VUnitScriptLocation=" + self.script
- return scriptsstr + "\n" + "eclipse.preferences.version=1\n"
+ script_string = "VUnitScriptLocation=" + self.script
+ return script_string + "\n" + "eclipse.preferences.version=1\n"
-class SigasiProjectCreator:
+class SigasiProject:
"""This class helps you to easily create a Sigasi project (".project")
and library mapping (".library_mapping.xml") file.
It will also create a .settings folder if it doesn't yet exist, see ProjectVersionCreator.
@@ -374,49 +390,74 @@ class SigasiProjectCreator:
creator = SigasiProjectCreator(project_name, VhdlVersion.NINETY_THREE)
creator.add_link("test.vhd", "/home/heeckhau/shared/test.vhd")
creator.add_mapping("test.vhd", "myLib")
+ creator.set_languages(True, False) # for a VHDL only project
creator.write("/home/heeckhau/test/")
"""
- # TODO Verilog, mixed language or other VHDL versions are never detected at this point
- # Change such that VHDL or Verilog presence may be set from library mapping and options.
- def __init__(self, project_name, vhdl_version=VhdlVersion.NINETY_THREE, verilog_version=None):
- check_hdl_versions(vhdl_version, verilog_version)
- self.__libraryMappingFileCreator = LibraryMappingFileCreator(vhdl_version, verilog_version)
- self.__projectFileCreator = ProjectFileCreator(project_name, vhdl_version, verilog_version)
- self.__projectVersionCreators = []
- if vhdl_version is not None:
- self.__projectVersionCreators.append(ProjectVersionCreator(vhdl_version))
- if verilog_version is not None:
- self.__projectVersionCreators.append(ProjectVersionCreator(verilog_version))
- else:
- # Version file shouldn't hurt anyone
- self.__projectVersionCreators.append(ProjectVersionCreator(VerilogVersion.TWENTY_O_FIVE))
+ def __init__(self, options):
+ self.options = options
+ self.__libraryMappingFileCreator = LibraryMappingFileCreator()
+ self.__projectFileCreator = ProjectFileCreator(options.project_name)
self.verilog_includes = []
+ self.vhdl_version = None
+ self.verilog_version = None
+ self.languages_initialized = False
+
+ def set_languages(self, has_vhdl, has_verilog):
+ has_vhdl = has_vhdl or self.options.enable_vhdl
+ has_verilog = has_verilog or self.options.enable_verilog
+ if has_vhdl:
+ self.vhdl_version = self.options.vhdl_version
+ if has_verilog:
+ self.verilog_version = self.options.verilog_version
+ check_hdl_versions(self.vhdl_version, self.verilog_version)
+ self.__projectFileCreator.set_languages(self.vhdl_version, self.verilog_version)
+ self.__libraryMappingFileCreator.set_languages(self.vhdl_version, self.verilog_version)
+ self.languages_initialized = True
def add_link(self, name, location, folder=False):
- self.__projectFileCreator.add_link(name, posixpath(location), folder)
+ if folder and (location is None):
+ # virtual folder
+ self.__projectFileCreator.add_link(name, 'virtual:/virtual', folder)
+ else:
+ self.__projectFileCreator.add_link(name, posixpath(location), folder)
def add_mapping(self, path, library):
self.__libraryMappingFileCreator.add_mapping(posixpath(path), library)
+ def remove_mapping(self, path):
+ self.__libraryMappingFileCreator.remove_mapping(posixpath(path))
+
def unmap(self, path):
self.__libraryMappingFileCreator.unmap(posixpath(path))
+ def get_mapping(self, path):
+ return self.__libraryMappingFileCreator.get_mapping(path)
+
def add_verilog_include(self, path):
self.verilog_includes.append(path)
- def write(self, destination, force_vhdl=None, force_verilog=None, verilog_includes=None, verilog_defines=None, force_vunit=None):
- self.__projectFileCreator.write(destination, force_vhdl, force_verilog, force_vunit)
- self.__libraryMappingFileCreator.write(destination)
- for projectVersionCreator in self.__projectVersionCreators:
- projectVersionCreator.write(destination)
+ def write(self, destination, verilog_includes=None, verilog_defines=None, force_vunit=None):
+ abort_if_false(self.languages_initialized, "HDL languages must be set before writing the project")
+
+ if not isinstance(destination, pathlib.Path):
+ destination = pathlib.Path(destination)
+
+ self.__projectFileCreator.write(destination, force_vunit, self.options.force_overwrite)
+ self.__libraryMappingFileCreator.write(destination, self.options.force_overwrite)
+ if self.vhdl_version is not None:
+ ProjectVersionCreator(self.options.vhdl_version).write(destination, self.options.force_overwrite)
+ if self.verilog_version is not None:
+ ProjectVersionCreator(self.options.verilog_version).write(destination, self.options.force_overwrite)
self.verilog_includes.extend(verilog_includes or [])
if self.verilog_includes or verilog_defines:
verilog_prefs = ProjectPreferencesCreator('verilog', self.verilog_includes, verilog_defines)
- verilog_prefs.write(destination)
+ verilog_prefs.write(destination, self.options.force_overwrite)
if force_vunit:
vunit_prefs = VUnitPreferencesCreator()
- vunit_prefs.write(destination)
+ vunit_prefs.write(destination, self.options.force_overwrite)
+ encoding_prefs = ProjectEncodingCreator(self.options.encoding)
+ encoding_prefs.write(destination, self.options.force_overwrite)
def add_unisim(self, unisim_location):
self.add_link("Common Libraries/unisim", unisim_location, True)
@@ -434,9 +475,22 @@ def add_unimacro(self, unimacro_location):
def add_project_reference(self, name):
self.__projectFileCreator.add_project_reference(name)
- def add_uvm(self, uvm_location, uvm_library):
+ def add_uvm(self, uvm_location: pathlib.Path, uvm_library):
if uvm_location is not None:
- # TODO improve path handling
- self.add_link('Common Libraries/uvm', os.path.join(uvm_location, 'src'), True)
- self.add_mapping('Common Libraries/uvm/uvm_pkg.sv', uvm_library)
- self.add_verilog_include('Common Libraries/uvm')
+ self.add_link(pathlib.Path('Common Libraries/uvm'), uvm_location.joinpath('src'), True)
+ self.add_mapping(pathlib.Path('Common Libraries/uvm/uvm_pkg.sv'), uvm_library)
+ self.add_verilog_include(pathlib.Path('Common Libraries/uvm'))
+
+
+def project_location_path(my_path):
+ assert (not (str(my_path).startswith('PROJECT') or str(my_path).startswith('PARENT-'))), \
+ f'*OOPS* not expecting {my_path} here'
+ if pathlib.Path(my_path).is_absolute():
+ return my_path
+ parent_level = 0
+ while my_path.startswith('..'):
+ parent_level += 1
+ my_path = my_path[3::]
+ if parent_level == 0:
+ return my_path
+ return 'PARENT-' + str(parent_level) + '-PROJECT_LOC/' + my_path
diff --git a/src/SigasiProjectCreator/VerilogVersion.py b/src/SigasiProjectCreator/VerilogVersion.py
index 1dd9add..f2b8e1b 100644
--- a/src/SigasiProjectCreator/VerilogVersion.py
+++ b/src/SigasiProjectCreator/VerilogVersion.py
@@ -1,5 +1,6 @@
TWENTY_O_FIVE = "v2005"
+TWENTY_TWELVE = "sv2012"
def get_enums():
- return [TWENTY_O_FIVE]
+ return [TWENTY_O_FIVE, TWENTY_TWELVE]
diff --git a/src/SigasiProjectCreator/VhdlVersion.py b/src/SigasiProjectCreator/VhdlVersion.py
index 02e2689..0c2b061 100644
--- a/src/SigasiProjectCreator/VhdlVersion.py
+++ b/src/SigasiProjectCreator/VhdlVersion.py
@@ -3,7 +3,12 @@
NINETY_THREE = 93
TWENTY_O_TWO = 2002
TWENTY_O_EIGHT = 2008
+TWENTY_NINETEEN = 2019
def get_enums():
- return [NINETY_THREE, TWENTY_O_TWO, TWENTY_O_EIGHT]
+ return [NINETY_THREE, TWENTY_O_TWO, TWENTY_O_EIGHT, TWENTY_NINETEEN]
+
+
+def get_str_enums():
+ return [str(version) for version in get_enums()]
diff --git a/src/SigasiProjectCreator/XilinxProjectParser.py b/src/SigasiProjectCreator/XilinxProjectParser.py
new file mode 100644
index 0000000..f1e9886
--- /dev/null
+++ b/src/SigasiProjectCreator/XilinxProjectParser.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+"""
+ :copyright: (c) 2008-2023 Sigasi
+ :license: BSD, see LICENSE for more details.
+"""
+import xml.etree.ElementTree as eT
+import os
+
+from SigasiProjectCreator.ProjectFileParser import ProjectFileParser, project_file_parser, ProjectFileParserResult
+
+
+@project_file_parser('xise')
+class XilinxProjectParser(ProjectFileParser):
+ """Xilinx ISE project"""
+ def __init__(self):
+ super().__init__()
+
+ def parse_file(self, xilinx_file, options=None):
+ tree = eT.parse(xilinx_file)
+ root = tree.getroot()
+ schema = '{http://www.xilinx.com/XMLSchema}'
+ library_mapping = dict()
+
+ for f in root.findall('*/' + schema + 'file'):
+ if schema + 'type' in f.attrib:
+ schema_type = f.attrib[schema + 'type']
+ if schema_type == 'FILE_VHDL': # TODO VHDL only?
+ name = os.path.realpath(os.path.abspath(f.attrib[schema + 'name']))
+ lib = f.find(schema + 'library')
+ library = lib.attrib[schema + 'name'] if (lib is not None) else "work"
+ library_mapping[name] = library
+ return ProjectFileParserResult(library_mapping, None, None)
diff --git a/src/SigasiProjectCreator/__init__.py b/src/SigasiProjectCreator/__init__.py
index 8e13419..a70ae1b 100644
--- a/src/SigasiProjectCreator/__init__.py
+++ b/src/SigasiProjectCreator/__init__.py
@@ -1,6 +1,8 @@
+import sys
from os.path import abspath, normcase, splitdrive, join
from pathlib import PurePath
+
def absnormpath(p):
"""
Get a normalized absolute version of given path.
@@ -10,6 +12,14 @@ def absnormpath(p):
drive, tail = splitdrive(abspath(p))
return join(normcase(drive), tail)
+
def posixpath(p):
- "Convert a path to POSIX style, also on Windows."
+ """Convert a path to POSIX style, also on Windows."""
return PurePath(p).as_posix()
+
+
+def abort_if_false(condition, message, code=5):
+ """User-facing equivalent of assert"""
+ if not condition:
+ print(message)
+ sys.exit(code)
diff --git a/src/SigasiProjectCreator/convertCsvFileToLinks.py b/src/SigasiProjectCreator/convertCsvFileToLinks.py
deleted file mode 100755
index 88ab587..0000000
--- a/src/SigasiProjectCreator/convertCsvFileToLinks.py
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-"""
- :copyright: (c) 2008-2023 Sigasi
- :license: BSD, see LICENSE for more details.
-"""
-import os
-
-from SigasiProjectCreator.Creator import SigasiProjectCreator
-from SigasiProjectCreator.ArgsAndFileParser import ArgsAndFileParser
-from SigasiProjectCreator import CsvParser
-from SigasiProjectCreator import VhdlVersion
-
-
-def get_file_name(entry):
- (folder, filename) = os.path.split(os.path.abspath(entry))
- return filename
-
-
-def main():
- parser = ArgsAndFileParser(CsvParser.usage)
- (project_name, _, destination, entries) = parser.parse_args_and_file(CsvParser.parse_file)
-
- creator = SigasiProjectCreator(project_name, VhdlVersion.NINETY_THREE)
-
- for path, library in entries.items():
- file_name = get_file_name(path)
- link_type = os.path.isdir(path)
- creator.add_link(file_name, os.path.abspath(path), link_type)
- creator.add_mapping(file_name, library)
-
- creator.write(destination, force_vunit=True)
-
-
-if __name__ == '__main__':
- main()
diff --git a/src/SigasiProjectCreator/convertCsvFileToTree.py b/src/SigasiProjectCreator/convertCsvFileToTree.py
deleted file mode 100755
index 02ee4b6..0000000
--- a/src/SigasiProjectCreator/convertCsvFileToTree.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-"""
- :copyright: (c) 2008-2023 Sigasi
- :license: BSD, see LICENSE for more details.
-"""
-from SigasiProjectCreator import CsvParser
-from SigasiProjectCreator import ConverterHelper
-
-
-def main():
- ConverterHelper.parse_and_create_project(CsvParser.usage, CsvParser.parse_file)
-
-
-if __name__ == '__main__':
- main()
diff --git a/src/SigasiProjectCreator/convertDotFtoCsv.py b/src/SigasiProjectCreator/convertDotFtoCsv.py
deleted file mode 100644
index 741d4df..0000000
--- a/src/SigasiProjectCreator/convertDotFtoCsv.py
+++ /dev/null
@@ -1,76 +0,0 @@
-"""
- :copyright: (c) 2008-2023 Sigasi
- :license: BSD, see LICENSE for more details.
-"""
-
-# Exit codes:
-# 1 : file not found
-# 2 : relative path expected, but absolute path given
-
-from SigasiProjectCreator.DotF.parseFile import parse_dotf
-import sys
-import os
-import csv
-
-def isabspath(path):
- s_path = str(path)
- if s_path.startswith('\\') or s_path.startswith('/') or s_path[1] == ':' or s_path.startswith('$'):
- return True
- return os.path.isabs(path)
-
-
-def rebase_file(filename, dotfdir):
- hdlpath = os.path.expandvars(filename)
- if not isabspath(hdlpath):
- hdlpath = os.path.join(dotfdir, hdlpath)
- hdlpath = os.path.normpath(hdlpath)
- return hdlpath
-
-
-def convertDotFtoCsv(filename):
- if not os.path.isfile(filename):
- print("*ERROR* File " + filename + " does not exist")
- sys.exit(1)
- if os.path.isabs(filename):
- print("*ERROR* must use a relative path, but " + filename + " is absolute")
- sys.exit(2)
-
- dotfdir = os.path.dirname(filename)
- dotfname = os.path.basename(filename)
- csvfname = str(os.path.splitext(dotfname)[0]) + ".csv"
-
- include_path = []
- filecontent = parse_dotf(filename)
-
- print("Writing CSV: " + csvfname)
-
- with open(csvfname, "w", newline='') as csvfile:
- csvwriter = csv.writer(csvfile)
- for option in filecontent:
- if isinstance(option, list):
- if option[0].startswith("-makelib"):
- newlib = option[0].split(' ')[1].split('/')[-1]
- print('Library ' + newlib)
- for fn in option:
- if not (fn.startswith("+") or fn.startswith("-")):
- csvwriter.writerow([newlib, rebase_file(str(fn).strip('"'), dotfdir)])
- else:
- print('Unexpected multiline option: ' + option[0])
- else:
- bare_option = str(option).strip('"')
- if bare_option.startswith("+incdir"):
- print("*include path* " + rebase_file(bare_option[8:], dotfdir))
- include_path.append(bare_option[8:])
- elif bare_option.startswith("+") or bare_option.startswith("-"):
- print("*unknown option* " + bare_option)
- else:
- # print("*file* " + bare_option + " => " + rebase_file(bare_option, dotfdir))
- csvwriter.writerow(['work', rebase_file(bare_option, dotfdir)])
-
-if __name__ == '__main__':
- print(sys.argv)
- if len(sys.argv) > 1:
- convertDotFtoCsv(sys.argv[1])
- else:
- print('Usage: convertDotFtoCsv.py ')
- exit(1)
diff --git a/src/SigasiProjectCreator/convertHdpProjectToSigasiProject.py b/src/SigasiProjectCreator/convertHdpProjectToSigasiProject.py
deleted file mode 100644
index fd5ff9c..0000000
--- a/src/SigasiProjectCreator/convertHdpProjectToSigasiProject.py
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-"""
- :copyright: (c) 2008-2023 Sigasi
- :license: BSD, see LICENSE for more details.
-"""
-from configparser import ConfigParser
-
-from SigasiProjectCreator import ConverterHelper
-
-usage = """usage: %prog project-name hdp-file [destination]
-
-destination is the current directory by default
-example: %prog MyProjectName myproject.hdp
-"""
-
-
-def parse_hdp_file(hdp_file):
- config = ConfigParser()
- config.read(hdp_file)
- entries = config.items("hdl")
- return {lib: path for path, lib in entries}
-
-
-def main():
- ConverterHelper.parse_and_create_project(usage, parse_hdp_file)
-
-
-if __name__ == '__main__':
- main()
diff --git a/src/SigasiProjectCreator/convertXilinxISEToSigasiProject.py b/src/SigasiProjectCreator/convertXilinxISEToSigasiProject.py
deleted file mode 100644
index 2245780..0000000
--- a/src/SigasiProjectCreator/convertXilinxISEToSigasiProject.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-"""
- :copyright: (c) 2008-2023 Sigasi
- :license: BSD, see LICENSE for more details.
-"""
-import xml.etree.ElementTree as eT
-
-from SigasiProjectCreator import ConverterHelper
-
-usage = """usage: %prog project-name Xilinx-file [destination]
-
-destination is the current directory by default
-example: %prog MyProjectName project.xise
-"""
-
-
-def parse_xilinx_file(xilinx_file):
- entries = dict()
- tree = eT.parse(xilinx_file)
- root = tree.getroot()
- schema = '{http://www.xilinx.com/XMLSchema}'
-
- for f in root.findall('*/' + schema + 'file'):
- if schema + 'type' in f.attrib:
- schema_type = f.attrib[schema + 'type']
- if schema_type == 'FILE_VHDL':
- name = f.attrib[schema + 'name']
- lib = f.find(schema + 'library')
- library = lib.attrib[schema + 'name'] if (lib is not None) else "work"
- entries[name] = library
-
- return entries
-
-
-def main():
- ConverterHelper.parse_and_create_project(usage, parse_xilinx_file)
-
-
-if __name__ == '__main__':
- main()
diff --git a/src/SigasiProjectCreator/createSigasiProjectFromListOfFiles.py b/src/SigasiProjectCreator/createSigasiProjectFromListOfFiles.py
deleted file mode 100755
index 259291b..0000000
--- a/src/SigasiProjectCreator/createSigasiProjectFromListOfFiles.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-"""
- :copyright: (c) 2008-2023 Sigasi
- :license: BSD, see LICENSE for more details.
-"""
-import os
-
-from SigasiProjectCreator.ArgsAndFileParser import ArgsAndFileParser
-from SigasiProjectCreator.Creator import SigasiProjectCreator
-from SigasiProjectCreator import VhdlVersion
-import argparse
-
-usage = """usage: %prog project-name hdl-file hdl-file...
-
- this script creates a Sigasi project in the current working directory:
- * adds one linked folder to the project that points to the common
- folder of all listed hdl-files
- * unmaps all hdl-files in the common folder, except the listed files.
- These files are mapped to the 'work' library
-example: %prog MyProjectName foo.vhdl bar.sv
-"""
-
-
-def main():
- parser = argparse.ArgumentParser(prog='SigasiProjectCreator')
- parser.add_argument('project_name', help='project name')
- parser.add_argument('input_files', help='input files', nargs='+')
- args = parser.parse_args()
- project_name = args.project_name
- hdl_files = args.input_files
- destination = os.getcwd()
-
- # Find common directory of the hdl files
- abs_paths = [os.path.abspath(x) for x in hdl_files]
- folder = os.path.dirname(os.path.commonprefix([p + os.path.sep for p in abs_paths]))
-
- sigasi_project_file_creator = SigasiProjectCreator(project_name, VhdlVersion.NINETY_THREE)
- # Create Project File and add a link the common source folder
- folder_name = os.path.basename(os.path.normpath(folder))
- sigasi_project_file_creator.add_link(folder_name, folder, True)
-
- # Create Library Mapping File
- # Unmap everything except the list of files (map those to work)
- sigasi_project_file_creator.unmap("/")
- for path in abs_paths:
- relative_file_path = os.path.relpath(path, folder)
- sigasi_project_file_creator.add_mapping(folder_name + "/" + relative_file_path, "work")
-
- sigasi_project_file_creator.write(destination)
-
-
-if __name__ == '__main__':
- main()
diff --git a/src/convertDotFtoSigasiProject.py b/src/convertDotFtoSigasiProject.py
deleted file mode 100644
index 2f02c67..0000000
--- a/src/convertDotFtoSigasiProject.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""
- :copyright: (c) 2008-2023 Sigasi
- :license: BSD, see LICENSE for more details.
-"""
-from SigasiProjectCreator import ConverterHelper
-from SigasiProjectCreator.DotF import DotFfileParser
-
-
-def main():
- ConverterHelper.parse_and_create_project(DotFfileParser.usage, DotFfileParser.parse_file)
-
-
-if __name__ == '__main__':
- main()
diff --git a/src/createSigasiProject.py b/src/createSigasiProject.py
new file mode 100644
index 0000000..bce925d
--- /dev/null
+++ b/src/createSigasiProject.py
@@ -0,0 +1,20 @@
+"""
+ :copyright: (c) 2008-2023 Sigasi
+ :license: BSD, see LICENSE for more details.
+"""
+import sys
+
+from SigasiProjectCreator.ProjectCreator import get_project_creator
+from SigasiProjectCreator.ProjectOptions import ProjectOptions
+from SigasiProjectCreator import CsvParser
+from SigasiProjectCreator.DotF import DotFfileParser
+from SigasiProjectCreator.HdpProjectParser import HdpParser
+from SigasiProjectCreator.XilinxProjectParser import XilinxProjectParser
+
+
+def main(args):
+ get_project_creator(ProjectOptions(args)).create_project()
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/tests/ConvertCsvFileToLinksTest.py b/tests/ConvertCsvFileToLinksTest.py
deleted file mode 100644
index 2c9b863..0000000
--- a/tests/ConvertCsvFileToLinksTest.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- :copyright: (c) 2008-2023 Sigasi
- :license: BSD, see LICENSE for more details.
-"""
-import unittest
-import sys
-import tempfile
-import shutil
-import os
-import filecmp
-import SigasiProjectCreator.convertCsvFileToLinks as csvConverter
-
-
-class ConvertCsvFileToLinksTest(unittest.TestCase):
- def setUp(self):
- self.temp_dir = tempfile.mkdtemp()
-
- def tearDown(self):
- shutil.rmtree(self.temp_dir)
-
- def test_main(self):
- wd = os.path.dirname(os.path.realpath(__file__))
- links_dir = os.path.join(wd, "test-files/links")
- csv_file = os.path.join(links_dir, "compilation_order.csv")
- sys.argv = [sys.argv[0], "tutorial", csv_file, links_dir]
- csvConverter.main()
- result = filecmp.dircmp(links_dir, self.temp_dir)
- self.assertTrue(not result.report())
diff --git a/tests/ConvertCsvFileToTreeTest.py b/tests/ConvertCsvFileToTreeTest.py
deleted file mode 100644
index 2642216..0000000
--- a/tests/ConvertCsvFileToTreeTest.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- :copyright: (c) 2008-2023 Sigasi
- :license: BSD, see LICENSE for more details.
-"""
-import unittest
-import sys
-import tempfile
-import shutil
-import os
-import filecmp
-import SigasiProjectCreator.convertCsvFileToTree as csvConverter
-
-
-class ConvertCsvFileToTreeTest(unittest.TestCase):
- def setUp(self):
- self.temp_dir = tempfile.mkdtemp()
-
- def tearDown(self):
- shutil.rmtree(self.temp_dir)
-
- def test_main(self):
- wd = os.path.dirname(os.path.realpath(__file__))
- tree_dir = os.path.join(wd, "test-files/tree")
- csv_file = os.path.join(tree_dir, "compilation_order.csv")
- sys.argv = [sys.argv[0], "tutorial", csv_file, self.temp_dir]
- csvConverter.main()
- result = filecmp.dircmp(tree_dir, self.temp_dir)
- self.assertTrue(not result.report())
diff --git a/tests/CreateSigasiProjectFromListOfFilesTest.py b/tests/CreateSigasiProjectFromListOfFilesTest.py
deleted file mode 100644
index 03a25aa..0000000
--- a/tests/CreateSigasiProjectFromListOfFilesTest.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- :copyright: (c) 2008-2023 Sigasi
- :license: BSD, see LICENSE for more details.
-"""
-import unittest
-import sys
-import tempfile
-import shutil
-import os
-import filecmp
-import SigasiProjectCreator.createSigasiProjectFromListOfFiles as sigasiProjectCreator
-
-
-class CreateSigasiProjectFromListOfFilesTest(unittest.TestCase):
- def setUp(self):
- self.temp_dir = tempfile.mkdtemp()
- self.old_path = os.getcwd()
-
- def tearDown(self):
- shutil.rmtree(self.temp_dir)
- os.chdir(self.old_path)
-
- def test_main(self):
- wd = os.path.dirname(os.path.realpath(__file__))
- list_dir = os.path.join(wd, "test-files/list")
- # Be sure to cd back to the original dir later on
- os.chdir(self.temp_dir)
- files = ["testbench.vhd", "dut.vhd", "clock_generator.vhd", "foo/foo.vhd"]
- file_paths = [os.path.join(wd, "tutorial" + f) for f in files]
- sys.argv = [sys.argv[0], "list"]
- for path in file_paths:
- sys.argv.append(path)
- sigasiProjectCreator.main()
- result = filecmp.dircmp(list_dir, self.temp_dir)
- self.assertTrue(not result.report())
- os.chdir(wd)
diff --git a/tests/DotFfileParserTest.py b/tests/DotFfileParserTest.py
index 8f8a3f1..fcfd83d 100644
--- a/tests/DotFfileParserTest.py
+++ b/tests/DotFfileParserTest.py
@@ -1,127 +1,131 @@
-import os.path
+import pathlib
import unittest
-from SigasiProjectCreator.DotF.DotFfileParser import parse_file
+
+from SigasiProjectCreator.ProjectOptions import ProjectOptions
+from SigasiProjectCreator.DotF.DotFfileParser import DotFfileParser
+
class DotFfileParserTest(unittest.TestCase):
+ def setUp(self):
+ command_line_options = ['the_project', 'tests/test-files/tree/compilation_order.csv']
+ self.options = ProjectOptions(command_line_options)
+
def test_basic(self):
self.maxDiff = None
input_file = "tests/test-files/dotFparser/test1.f"
- result = parse_file(input_file)
- base_path = os.path.abspath(os.path.join(os.path.dirname(input_file), '../../../..'))
+ result = DotFfileParser().parse_file(input_file, self.options)
expected_library_mapping = {
- f'{base_path}/bench/verilog/stainlesssteel/ram_d1.sv': 'work',
- f'{base_path}/bench/verilog/stainlesssteel/ram_d2.sv': 'work',
- f'{base_path}/bench/verilog/stainlesssteel/ram_dp.sv': 'work',
- f'{base_path}/bench/verilog/stainlesssteel/ram_p2.sv': 'work',
- f'{base_path}/bench/verilog/stainlesssteel/ram_sp.sv': 'work',
- f'{base_path}/bench/verilog/stainlesssteel/glbl.sv': 'work',
- f'{base_path}/bench/verilog/stainlesssteel/m_debug.sv': 'work',
- f'{base_path}/bench/verilog/stainlesssteel/m_testbench.sv': 'work',
- f'{base_path}/rtl/verilog/soc/m_soc.sv': 'work',
- f'{base_path}/rtl/verilog/soc/m_io_cell.sv': 'work'
+ pathlib.Path('../bench/verilog/stainlesssteel/ram_d1.sv').absolute().resolve(): 'work',
+ pathlib.Path('../bench/verilog/stainlesssteel/ram_d2.sv').absolute().resolve(): 'work',
+ pathlib.Path('../bench/verilog/stainlesssteel/ram_dp.sv').absolute().resolve(): 'work',
+ pathlib.Path('../bench/verilog/stainlesssteel/ram_p2.sv').absolute().resolve(): 'work',
+ pathlib.Path('../bench/verilog/stainlesssteel/ram_sp.sv').absolute().resolve(): 'work',
+ pathlib.Path('../bench/verilog/stainlesssteel/glbl.sv').absolute().resolve(): 'work',
+ pathlib.Path('../bench/verilog/stainlesssteel/m_debug.sv').absolute().resolve(): 'work',
+ pathlib.Path('../bench/verilog/stainlesssteel/m_testbench.sv').absolute().resolve(): 'work',
+ pathlib.Path('../rtl/verilog/soc/m_soc.sv').absolute().resolve(): 'work',
+ pathlib.Path('../rtl/verilog/soc/m_io_cell.sv').absolute().resolve(): 'work'
}
expected_includes = {
- '../rtl/verilog/pkg',
- '../bench/verilog/stainlesssteel'
+ pathlib.Path('../rtl/verilog/pkg').absolute().resolve(),
+ pathlib.Path('../bench/verilog/stainlesssteel').absolute().resolve()
}
expected_defines = []
self.assertDictEqual(result.library_mapping, expected_library_mapping, 'Library mapping mismatch')
- self.assertSetEqual(result.includes, expected_includes, 'Includes list mismatch')
- self.assertListEqual(result.defines, expected_defines, 'Defines list mismatch')
+ self.assertSetEqual(result.verilog_includes, expected_includes, 'Includes list mismatch')
+ self.assertListEqual(result.verilog_defines, expected_defines, 'Defines list mismatch')
def test_continuation(self):
self.maxDiff = None
input_file = "tests/test-files/dotFparser/continuation.f"
- result = parse_file(input_file)
+ result = DotFfileParser().parse_file(input_file, self.options)
expected_library_mapping = {
- "D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/axi4stream_vip_axi4streampc.sv": 'vendor_vip',
- "D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/axi_vip_axi4pc.sv": 'vendor_vip',
- "D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/xil_common_vip_pkg.sv": 'vendor_vip',
- "D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/axi4stream_vip_pkg.sv": 'vendor_vip',
- "D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/axi_vip_pkg.sv": 'vendor_vip',
- "D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/axi4stream_vip_if.sv": 'vendor_vip',
- "D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/axi_vip_if.sv": 'vendor_vip',
- "D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/clk_vip_if.sv": 'vendor_vip',
- "D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/rst_vip_if.sv": 'vendor_vip',
- "D:/Vendor/Tool/2018.2/data/ip/xpm/xpm_cdc/hdl/xpm_cdc.sv": 'defaultlib',
- "D:/Vendor/Tool/2018.2/data/ip/xpm/xpm_fifo/hdl/xpm_fifo.sv": 'defaultlib',
- "D:/Vendor/Tool/2018.2/data/ip/xpm/xpm_memory/hdl/xpm_memory.sv": 'defaultlib',
- "D:/Vendor/Tool/2018.2/data/ip/xpm/xpm_VCOMP.vhd": 'xpm'
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/axi4stream_vip_axi4streampc.sv"): 'vendor_vip',
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/axi_vip_axi4pc.sv"): 'vendor_vip',
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/xil_common_vip_pkg.sv"): 'vendor_vip',
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/axi4stream_vip_pkg.sv"): 'vendor_vip',
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/axi_vip_pkg.sv"): 'vendor_vip',
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/axi4stream_vip_if.sv"): 'vendor_vip',
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/axi_vip_if.sv"): 'vendor_vip',
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/clk_vip_if.sv"): 'vendor_vip',
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/vendor_vip/hdl/rst_vip_if.sv"): 'vendor_vip',
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/ip/xpm/xpm_cdc/hdl/xpm_cdc.sv"): 'defaultlib',
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/ip/xpm/xpm_fifo/hdl/xpm_fifo.sv"): 'defaultlib',
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/ip/xpm/xpm_memory/hdl/xpm_memory.sv"): 'defaultlib',
+ pathlib.Path("D:/Vendor/Tool/2018.2/data/ip/xpm/xpm_VCOMP.vhd"): 'xpm'
}
expected_includes = set()
expected_defines = []
self.assertDictEqual(result.library_mapping, expected_library_mapping, 'Library mapping mismatch')
- self.assertSetEqual(result.includes, expected_includes, 'Includes list mismatch')
- self.assertListEqual(result.defines, expected_defines, 'Defines list mismatch')
+ self.assertSetEqual(result.verilog_includes, expected_includes, 'Includes list mismatch')
+ self.assertListEqual(result.verilog_defines, expected_defines, 'Defines list mismatch')
def test_filelist(self):
self.maxDiff = None
input_file = "tests/test-files/dotFparser/filelist.f"
- result = parse_file(input_file)
- base_path = os.path.abspath(os.path.join(os.path.dirname(input_file), '../../..'))
+ result = DotFfileParser().parse_file(input_file, self.options)
expected_library_mapping = {
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_conv.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_lite_conv.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_r_conv.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_w_conv.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b_downsizer.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_decerr_slave.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_simple_fifo.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_wrap_cmd.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_incr_cmd.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_wr_cmd_fsm.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_rd_cmd_fsm.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_cmd_translator.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_b_channel.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_r_channel.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_aw_channel.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_ar_channel.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s.v': 'work',
- f'{base_path}/ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_some_protocol_converter.v': 'work',
- f'{base_path}/bd/design_1/ip/design_1_auto_pc_0/sim/design_1_auto_pc_0.v': 'work',
- f'{base_path}/bd/design_1/hdl/design_1.vhd': 'work',
- f'{base_path}/tests/test-files/dotFparser/glbl.v': 'work'
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_conv.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_lite_conv.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_r_conv.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_w_conv.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b_downsizer.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_decerr_slave.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_simple_fifo.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_wrap_cmd.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_incr_cmd.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_wr_cmd_fsm.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_rd_cmd_fsm.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_cmd_translator.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_b_channel.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_r_channel.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_aw_channel.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s_ar_channel.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b2s.v').absolute().resolve(): 'work',
+ pathlib.Path('ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_some_protocol_converter.v').absolute().resolve(): 'work',
+ pathlib.Path('bd/design_1/ip/design_1_auto_pc_0/sim/design_1_auto_pc_0.v').absolute().resolve(): 'work',
+ pathlib.Path('bd/design_1/hdl/design_1.vhd').absolute().resolve(): 'work',
+ pathlib.Path('tests/test-files/dotFparser/glbl.v').absolute().resolve(): 'work'
}
expected_includes = set()
expected_defines = []
self.assertDictEqual(result.library_mapping, expected_library_mapping, 'Library mapping mismatch')
- self.assertSetEqual(result.includes, expected_includes, 'Includes list mismatch')
- self.assertListEqual(result.defines, expected_defines, 'Defines list mismatch')
+ self.assertSetEqual(result.verilog_includes, expected_includes, 'Includes list mismatch')
+ self.assertListEqual(result.verilog_defines, expected_defines, 'Defines list mismatch')
def test_variable(self):
self.maxDiff = None
- input_file = "tests/test-files/dotFparser/variable.f"
- result = parse_file(input_file)
- base_path = str(os.path.abspath(os.path.join(os.path.dirname(input_file), '.')))
+ input_file = pathlib.Path("tests/test-files/dotFparser/variable.f")
+ result = DotFfileParser().parse_file(input_file, self.options)
expected_library_mapping = {
- '${FUBAR_HOME}/src/fubar_pkg.sv': 'work',
- f'{base_path}/vw_wd_g2u_if.sv': 'work',
- f'{base_path}/vw_wd_g2u_test.sv': 'work',
- f'{base_path}/vw_wd_g2u_top.sv': 'work',
+ pathlib.Path('${FUBAR_HOME}/src/fubar_pkg.sv'): 'work',
+ pathlib.Path('tests/test-files/dotFparser/vw_wd_g2u_if.sv').absolute().resolve(): 'work',
+ pathlib.Path('tests/test-files/dotFparser/vw_wd_g2u_test.sv').absolute().resolve(): 'work',
+ pathlib.Path('tests/test-files/dotFparser/vw_wd_g2u_top.sv').absolute().resolve(): 'work',
}
- expected_includes = {'$FUBAR_HOME/src'}
+ expected_includes = {pathlib.Path('$FUBAR_HOME/src')}
expected_defines = []
self.assertDictEqual(result.library_mapping, expected_library_mapping, 'Library mapping mismatch')
- self.assertSetEqual(result.includes, expected_includes, 'Includes list mismatch')
- self.assertListEqual(result.defines, expected_defines, 'Defines list mismatch')
+ self.assertSetEqual(result.verilog_includes, expected_includes, 'Includes list mismatch')
+ self.assertListEqual(result.verilog_defines, expected_defines, 'Defines list mismatch')
def test_wildcard(self):
self.maxDiff = None
input_file = "tests/test-files/dotFparser/wildcard.f"
- base_path1 = str(os.path.abspath(os.path.join(os.path.dirname(input_file), '..')))
- base_path2 = str(os.path.abspath(os.path.join(os.path.dirname(input_file), '../..')))
- result = parse_file(input_file)
+ result = DotFfileParser().parse_file(input_file, self.options)
expected_library_mapping = {
- '/usr/eda/dk/vendor/tech/verilog/*.v': 'work',
- f'{base_path2}/synthesis/image_average.v': 'work',
- f'{base_path1}/tb/tb_image.vhd': 'work',
- f'{base_path2}/rtl/image_ram.vhd': 'work'
+ pathlib.Path('tests/test-files/dotFparser/../tutorial/clock_generator.vhd').absolute().resolve(): 'work',
+ pathlib.Path('tests/test-files/dotFparser/../tutorial/dut.vhd').absolute().resolve(): 'work',
+ pathlib.Path('tests/test-files/dotFparser/../tutorial/testbench.vhd').absolute().resolve(): 'work',
+ pathlib.Path('/absolute/path/synthesis/image_average.v'): 'work',
+ pathlib.Path('tests/test-files/dotFparser/../tb/tb_image.vhd').absolute().resolve(): 'work',
+ pathlib.Path('tests/test-files/dotFparser/../../rtl/image_ram.vhd').absolute().resolve(): 'work'
}
expected_includes = set()
expected_defines = []
self.assertDictEqual(result.library_mapping, expected_library_mapping, 'Library mapping mismatch')
- self.assertSetEqual(result.includes, expected_includes, 'Includes list mismatch')
- self.assertListEqual(result.defines, expected_defines, 'Defines list mismatch')
+ self.assertSetEqual(result.verilog_includes, expected_includes, 'Includes list mismatch')
+ self.assertListEqual(result.verilog_defines, expected_defines, 'Defines list mismatch')
if __name__ == '__main__':
diff --git a/tests/LibraryMappingFileCreatorTest.py b/tests/LibraryMappingFileCreatorTest.py
index 1a64664..6d1c889 100644
--- a/tests/LibraryMappingFileCreatorTest.py
+++ b/tests/LibraryMappingFileCreatorTest.py
@@ -5,7 +5,8 @@
"""
import unittest
-from SigasiProjectCreator.Creator import LibraryMappingFileCreator
+from SigasiProjectCreator import VhdlVersion, VerilogVersion
+from SigasiProjectCreator.SigasiProject import LibraryMappingFileCreator
from string import Template
@@ -28,6 +29,7 @@ def setUp(self):
def test_empty_file(self):
expected = mappings_template
+ self.creator.set_languages(VhdlVersion.TWENTY_O_EIGHT, None)
self.assertEqual(expected.substitute(after=""), str(self.creator))
def test_simple_mapping(self):
@@ -38,6 +40,7 @@ def test_simple_mapping(self):
self.creator.add_mapping(loc, lib)
self.creator.add_mapping("", "not mapped")
+ self.creator.set_languages(VhdlVersion.TWENTY_O_EIGHT, VerilogVersion.TWENTY_O_FIVE)
self.assertEqual(expected, str(self.creator))
def test_duplicate_mapping(self):
@@ -48,4 +51,5 @@ def test_duplicate_mapping(self):
self.creator.add_mapping(loc, "test")
self.creator.add_mapping(loc, lib)
+ self.creator.set_languages(VhdlVersion.TWENTY_O_EIGHT, None)
self.assertEqual(expected, str(self.creator))
diff --git a/tests/ProjectCreatorTest.py b/tests/ProjectCreatorTest.py
new file mode 100644
index 0000000..0c4e40f
--- /dev/null
+++ b/tests/ProjectCreatorTest.py
@@ -0,0 +1,488 @@
+import pathlib
+import shutil
+import unittest
+import os
+
+from SigasiProjectCreator import CsvParser
+from SigasiProjectCreator.ProjectCreator import ProjectCreator, get_parser_for_type, get_design_root_folder, \
+ get_design_folders, get_design_subtrees, get_unique_name, get_rel_or_abs_path, ProjectCreatorSimulator, \
+ ProjectCreatorLinkedFilesFlat, ProjectCreatorLinkedFilesTree, ProjectCreatorLinkedFolders, ProjectCreatorInPlace
+from SigasiProjectCreator.ProjectFileParser import ProjectFileParser
+from SigasiProjectCreator.ProjectOptions import ProjectOptions
+from SigasiProjectCreator.DotF import DotFfileParser
+from SigasiProjectCreator.HdpProjectParser import HdpParser
+from SigasiProjectCreator.XilinxProjectParser import XilinxProjectParser
+
+
+class ProjectCreatorTest(unittest.TestCase):
+ def setUp(self):
+ command_line_options = ['the_project', 'tests/test-files/tree/compilation_order.csv']
+ self.options = ProjectOptions(command_line_options)
+ self.project_creator = ProjectCreator(self.options)
+
+ def test_abs_or_rel_path_rel_in(self):
+ destination_folder = pathlib.Path('foo').absolute().as_posix()
+ command_line_options = ['the_project', 'tests/test-files/tree/compilation_order.csv', '-d', destination_folder]
+ self.options = ProjectOptions(command_line_options)
+ design_path = pathlib.Path('tests/test-files/tutorial/testbench.vhd')
+ result = get_rel_or_abs_path(design_path, self.project_creator.project_root, self.options)
+ self.assertEqual(result, design_path)
+
+ def test_abs_or_rel_path_abs(self):
+ destination_folder = pathlib.Path('foo').absolute().as_posix()
+ command_line_options = ['the_project', 'tests/test-files/tree/compilation_order.csv', '-d', destination_folder]
+ self.options = ProjectOptions(command_line_options)
+ self.project_creator = ProjectCreator(self.options)
+ design_path = pathlib.Path('tests/test-files/tutorial/testbench.vhd').absolute()
+ result = get_rel_or_abs_path(design_path, self.project_creator.project_root, self.options)
+ self.assertEqual(result, design_path.absolute())
+
+ def test_abs_or_rel_path_rel(self):
+ destination_folder = pathlib.Path('foo').absolute()
+ command_line_options = ['the_project', 'tests/test-files/tree/compilation_order.csv',
+ '-d', destination_folder.as_posix(),
+ '--rel-path', 'fooh',
+ '--rel-path', 'tests/test-files']
+ self.options = ProjectOptions(command_line_options)
+ self.project_creator = ProjectCreator(self.options)
+ design_path = pathlib.Path('tests/test-files/tutorial/testbench.vhd').absolute()
+ self.assertTrue(self.options.use_relative_path(design_path))
+ result = get_rel_or_abs_path(design_path, self.project_creator.project_root, self.options)
+ self.assertEqual(result, pathlib.Path(os.path.relpath(design_path, destination_folder)))
+
+ def test_check_and_create_virtual_folder(self):
+ result = self.project_creator.sigasi_project._SigasiProject__projectFileCreator._ProjectFileCreator__links
+ self.assertEqual(result, [])
+ self.project_creator.check_and_create_virtual_folder(pathlib.Path('foo/bar/file.vhd'))
+ result = self.project_creator.sigasi_project._SigasiProject__projectFileCreator._ProjectFileCreator__links
+ expected = [[pathlib.Path('foo'), 'virtual:/virtual', True, False],
+ [pathlib.Path('foo/bar'), 'virtual:/virtual', True, False]]
+ self.assertEqual(result, expected)
+
+ def test_check_and_create_linked_folder(self):
+ # set_project_root('project_folder')
+ self.project_creator.check_and_create_linked_folder(pathlib.Path('foo/bar/file.vhd'),
+ pathlib.Path('/here/there'))
+ result = self.project_creator.sigasi_project._SigasiProject__projectFileCreator._ProjectFileCreator__links
+ expected = [[pathlib.Path('foo'), 'virtual:/virtual', True, False],
+ [pathlib.Path('foo/bar'), 'virtual:/virtual', True, False],
+ [pathlib.Path('foo/bar/file.vhd'), '/here/there', True, True]]
+ self.assertEqual(result, expected)
+
+ def test_uniquify_project_path_none(self):
+ result = get_unique_name(pathlib.Path('/my/path/foo/bar.vhd'), None)
+ self.assertEqual(result, pathlib.Path('/my/path/foo/bar.vhd'))
+
+ def test_uniquify_project_path_empty_list(self):
+ result = get_unique_name(pathlib.Path('/my/path/foo/bar.vhd'), [])
+ self.assertEqual(result, pathlib.Path('/my/path/foo/bar.vhd'))
+
+ def test_uniquify_project_path_not_in_list(self):
+ path_list = [
+ pathlib.Path('/my/path/foo/bar.v'),
+ pathlib.Path('/my/path/foo/bar.vhdl')
+ ]
+ result = get_unique_name(pathlib.Path('/my/path/foo/bar.vhd'), path_list)
+ self.assertEqual(result, pathlib.Path('/my/path/foo/bar.vhd'))
+
+ def test_uniquify_project_path_in_list(self):
+ path_list = [
+ pathlib.Path('/my/path/foo/bar.v'),
+ pathlib.Path('/my/path/foo/bar.vhd'),
+ pathlib.Path('/my/path/foo/bar.vhdl')
+ ]
+ result = get_unique_name(pathlib.Path('/my/path/foo/bar.vhd'), path_list)
+ self.assertEqual(result, pathlib.Path('/my/path/foo/bar_1.vhd'))
+
+ def test_uniquify_project_path_in_list_multi(self):
+ path_list = [
+ pathlib.Path('/my/path/foo/bar.v'),
+ pathlib.Path('/my/path/foo/bar.vhd'),
+ pathlib.Path('/my/path/foo/bar_1.vhd'),
+ pathlib.Path('/my/path/foo/bar_2.vhd'),
+ pathlib.Path('/my/path/foo/bar_3.vhd'),
+ pathlib.Path('/my/path/foo/bar.vhdl')
+ ]
+ result = get_unique_name(pathlib.Path('/my/path/foo/bar.vhd'), path_list)
+ self.assertEqual(result, pathlib.Path('/my/path/foo/bar_4.vhd'))
+
+ def test_create_project_simulator(self):
+ self.maxDiff = None
+ self.project_creator = ProjectCreatorSimulator(self.options)
+ entries = {
+ pathlib.Path('/my/path/foo/bar.v'): 'work',
+ pathlib.Path('/my/path/foo/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo1/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo2/bar.vhd'): 'labor',
+ pathlib.Path('/my/path/foo3/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo/bar.vhdl'): 'work',
+ pathlib.Path('/my/path/foo/bahr.vhdl'): ['work', 'travail']
+ }
+ has_vhdl, has_verilog = self.project_creator.create_project_layout(entries)
+ self.assertTrue(has_vhdl)
+ self.assertTrue(has_verilog)
+ file_mapping = self.project_creator.sigasi_project._SigasiProject__projectFileCreator._ProjectFileCreator__links
+ expected = [['work', 'virtual:/virtual', True, False],
+ [pathlib.Path('work/bar.v'), '/my/path/foo/bar.v', False, True],
+ [pathlib.Path('work/bar.vhd'), '/my/path/foo/bar.vhd', False, True],
+ [pathlib.Path('work/bar_1.vhd'), '/my/path/foo1/bar.vhd', False, True],
+ ['labor', 'virtual:/virtual', True, False],
+ [pathlib.Path('labor/bar.vhd'), '/my/path/foo2/bar.vhd', False, True],
+ [pathlib.Path('work/bar_2.vhd'), '/my/path/foo3/bar.vhd', False, True],
+ [pathlib.Path('work/bar.vhdl'), '/my/path/foo/bar.vhdl', False, True],
+ [pathlib.Path('work/bahr.vhdl'), '/my/path/foo/bahr.vhdl', False, True],
+ ['travail', 'virtual:/virtual', True, False],
+ [pathlib.Path('travail/bahr.vhdl'), '/my/path/foo/bahr.vhdl', False, True]
+ ]
+ self.assertEqual(file_mapping, expected)
+ lib_mapping = self.project_creator.sigasi_project._SigasiProject__libraryMappingFileCreator._LibraryMappingFileCreator__entries
+ lib_expected = {
+ '/': 'not mapped',
+ 'work': 'work',
+ 'labor': 'labor',
+ 'travail': 'travail'
+ }
+ self.assertEqual(lib_mapping, lib_expected)
+
+ def test_create_project_links_flat(self):
+ self.maxDiff = None
+ self.project_creator = ProjectCreatorLinkedFilesFlat(self.options)
+ entries = {
+ pathlib.Path('/my/path/foo/bar.v'): 'work',
+ pathlib.Path('/my/path/foo/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo1/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo2/bar.vhd'): 'labor',
+ pathlib.Path('/my/path/foo3/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo/bar.vhdl'): 'work',
+ pathlib.Path('/my/path/foo/bahr.vhdl'): ['work', 'travail']
+ }
+ has_vhdl, has_verilog = self.project_creator.create_project_layout(entries)
+ self.assertTrue(has_vhdl)
+ self.assertTrue(has_verilog)
+ file_mapping = self.project_creator.sigasi_project._SigasiProject__projectFileCreator._ProjectFileCreator__links
+ expected = [[pathlib.Path('bar.v'), '/my/path/foo/bar.v', False, True],
+ [pathlib.Path('bar.vhd'), '/my/path/foo/bar.vhd', False, True],
+ [pathlib.Path('bar_1.vhd'), '/my/path/foo1/bar.vhd', False, True],
+ [pathlib.Path('bar_2.vhd'), '/my/path/foo2/bar.vhd', False, True],
+ [pathlib.Path('bar_3.vhd'), '/my/path/foo3/bar.vhd', False, True],
+ [pathlib.Path('bar.vhdl'), '/my/path/foo/bar.vhdl', False, True],
+ [pathlib.Path('bahr.vhdl'), '/my/path/foo/bahr.vhdl', False, True],
+ [pathlib.Path('bahr_1.vhdl'), '/my/path/foo/bahr.vhdl', False, True]
+ ]
+ self.assertEqual(file_mapping, expected)
+ lib_mapping = self.project_creator.sigasi_project._SigasiProject__libraryMappingFileCreator._LibraryMappingFileCreator__entries
+ lib_expected = {
+ '/': 'not mapped',
+ 'bahr.vhdl': 'work',
+ 'bahr_1.vhdl': 'travail',
+ 'bar.v': 'work',
+ 'bar.vhd': 'work',
+ 'bar.vhdl': 'work',
+ 'bar_1.vhd': 'work',
+ 'bar_2.vhd': 'labor',
+ 'bar_3.vhd': 'work'
+ }
+ self.assertEqual(lib_mapping, lib_expected)
+
+ def test_get_design_folders(self):
+ self.maxDiff = None
+ entries = {
+ pathlib.Path('/my/path/foo/bar.v'): 'work',
+ pathlib.Path('/my/path/foo/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo1/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo2/bar.vhd'): 'labor',
+ pathlib.Path('/my/path/foo3/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo/bar.vhdl'): 'work',
+ pathlib.Path('/my/path/foo/bahr.vhdl'): ['work', 'travail']
+ }
+ design_folders = get_design_folders(entries)
+ expected_folders = [
+ pathlib.Path('/my/path/foo'),
+ pathlib.Path('/my/path/foo1'),
+ pathlib.Path('/my/path/foo2'),
+ pathlib.Path('/my/path/foo3')
+ ]
+ self.assertEqual(design_folders, expected_folders)
+
+ def test_get_design_root_folder(self):
+ design_folders = [
+ pathlib.Path('/my/path/foo'),
+ pathlib.Path('/my/path/brol/foo1'),
+ pathlib.Path('/my/path/foo2'),
+ pathlib.Path('/my/path/some/deeper/path/foo3')
+ ]
+ self.assertEqual(get_design_root_folder(design_folders), pathlib.Path('/my/path'))
+
+ def test_get_design_subtrees(self):
+ # Note: folder lists must be sorted!
+ design_folders = [
+ pathlib.Path('/my/path/brol/foo1'),
+ pathlib.Path('/my/path/brol/foo1/foo2'),
+ pathlib.Path('/my/path/foo'),
+ pathlib.Path('/my/path/foo2'),
+ pathlib.Path('/my/path/some/deeper/path/foo3')
+ ]
+ design_subtrees = get_design_subtrees(design_folders)
+ expected_folders = [
+ pathlib.Path('/my/path/brol/foo1'),
+ pathlib.Path('/my/path/foo'),
+ pathlib.Path('/my/path/foo2'),
+ pathlib.Path('/my/path/some/deeper/path/foo3')
+ ]
+ self.assertEqual(design_subtrees, expected_folders)
+
+ def test_create_project_links_tree(self):
+ self.maxDiff = None
+ self.project_creator = ProjectCreatorLinkedFilesTree(self.options)
+ entries = {
+ pathlib.Path('/my/path/foo/bar.v'): 'work',
+ pathlib.Path('/my/path/foo/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo/one/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo/one/bars.vhd'): 'labor',
+ pathlib.Path('/my/path/foo2/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo/one/two/bar.vhdl'): 'work',
+ pathlib.Path('/my/path/foo/bahr.vhdl'): ['work', 'travail']
+ }
+ has_vhdl, has_verilog = self.project_creator.create_project_layout(entries)
+ self.assertTrue(has_vhdl)
+ self.assertTrue(has_verilog)
+ file_mapping = self.project_creator.sigasi_project._SigasiProject__projectFileCreator._ProjectFileCreator__links
+ print(f'**file mapping** {file_mapping}')
+ expected = [[pathlib.Path('foo'), 'virtual:/virtual', True, False],
+ [pathlib.Path('foo/bar.v'), '/my/path/foo/bar.v', False, True],
+ [pathlib.Path('foo/bar.vhd'), '/my/path/foo/bar.vhd', False, True],
+ [pathlib.Path('foo/one'), 'virtual:/virtual', True, False],
+ [pathlib.Path('foo/one/bar.vhd'), '/my/path/foo/one/bar.vhd', False, True],
+ [pathlib.Path('foo/one/bars.vhd'), '/my/path/foo/one/bars.vhd', False, True],
+ [pathlib.Path('foo2'), 'virtual:/virtual', True, False],
+ [pathlib.Path('foo2/bar.vhd'), '/my/path/foo2/bar.vhd', False, True],
+ [pathlib.Path('foo/one/two'), 'virtual:/virtual', True, False],
+ [pathlib.Path('foo/one/two/bar.vhdl'), '/my/path/foo/one/two/bar.vhdl', False, True],
+ [pathlib.Path('foo/bahr.vhdl'), '/my/path/foo/bahr.vhdl', False, True],
+ [pathlib.Path('foo/bahr_travail.vhdl'), '/my/path/foo/bahr.vhdl', False, True]
+ ]
+ print(f'##file mapping## {expected}')
+ self.assertEqual(file_mapping, expected)
+ lib_mapping = self.project_creator.sigasi_project._SigasiProject__libraryMappingFileCreator._LibraryMappingFileCreator__entries
+ lib_expected = {
+ '/': 'not mapped',
+ 'foo/bahr.vhdl': 'work',
+ 'foo/bahr_travail.vhdl': 'travail',
+ 'foo/bar.v': 'work',
+ 'foo/bar.vhd': 'work',
+ 'foo/one/two/bar.vhdl': 'work',
+ 'foo/one/bar.vhd': 'work',
+ 'foo/one/bars.vhd': 'labor',
+ 'foo2/bar.vhd': 'work'
+ }
+ self.assertEqual(lib_mapping, lib_expected)
+
+ def test_create_project_links_folders(self):
+ self.maxDiff = None
+ base_path = pathlib.Path('test_create_project_in_folders')
+ command_line_options = ['the_project', 'tests/test-files/tree/compilation_order.csv', '-d',
+ base_path.as_posix(), '--skip-check-exists']
+ self.options = ProjectOptions(command_line_options)
+ self.project_creator = ProjectCreatorLinkedFolders(self.options)
+ entries = {
+ pathlib.Path('/my/path/foo/bar.v'): 'work',
+ pathlib.Path('/my/path/foo/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo/one/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo/one/bars.vhd'): 'labor',
+ pathlib.Path('/my/path/foo2/bar.vhd'): 'work',
+ pathlib.Path('/my/path/foo/one/two/bar.vhdl'): 'work',
+ pathlib.Path('/my/path/foo/bahr.vhdl'): ['work', 'travail']
+ }
+ has_vhdl, has_verilog = self.project_creator.create_project_layout(entries)
+ self.assertTrue(has_vhdl)
+ self.assertTrue(has_verilog)
+ file_mapping = self.project_creator.sigasi_project._SigasiProject__projectFileCreator._ProjectFileCreator__links
+ print(f'**file mapping** {file_mapping}')
+ expected = [[pathlib.Path('foo'), '/my/path/foo', True, True],
+ [pathlib.Path('foo2'), '/my/path/foo2', True, True],
+ [pathlib.Path('foo/bahr_travail.vhdl'), '/my/path/foo/bahr.vhdl', False, True]
+ ]
+ print(f'##file mapping## {expected}')
+ self.assertEqual(file_mapping, expected)
+ lib_mapping = self.project_creator.sigasi_project._SigasiProject__libraryMappingFileCreator._LibraryMappingFileCreator__entries
+ lib_expected = {
+ '/': 'not mapped',
+ 'foo/bahr.vhdl': 'work',
+ 'foo/bahr_travail.vhdl': 'travail',
+ 'foo/bar.v': 'work',
+ 'foo/bar.vhd': 'work',
+ 'foo/one/two/bar.vhdl': 'work',
+ 'foo/one/bar.vhd': 'work',
+ 'foo/one/bars.vhd': 'labor',
+ 'foo2/bar.vhd': 'work'
+ }
+ self.assertEqual(lib_mapping, lib_expected)
+
+ # @unittest.skip # Path handling not OK!
+ def test_create_project_in_place(self):
+ self.maxDiff = None
+ base_path = pathlib.Path.cwd().joinpath('test_create_project_in_place')
+ command_line_options = ['the_project', 'tests/test-files/tree/compilation_order.csv', '-d',
+ base_path.as_posix(), '--skip-check-exists']
+ self.options = ProjectOptions(command_line_options)
+ self.project_creator = ProjectCreatorInPlace(self.options)
+
+ entries = {
+ base_path.joinpath('foo/bar.v'): 'work',
+ base_path.joinpath('foo/bar.vhd'): 'work',
+ base_path.joinpath('foo/one/bar.vhd'): 'work',
+ base_path.joinpath('foo/one/bars.vhd'): 'labor',
+ base_path.joinpath('foo2/bar.vhd'): 'work',
+ base_path.joinpath('foo/one/two/bar.vhdl'): 'work',
+ base_path.joinpath('foo/bahr.vhdl'): ['work', 'travail']
+ }
+ has_vhdl, has_verilog = self.project_creator.create_project_layout(entries)
+ self.assertTrue(has_vhdl)
+ self.assertTrue(has_verilog)
+ file_mapping = self.project_creator.sigasi_project._SigasiProject__projectFileCreator._ProjectFileCreator__links
+ print(f'**file mapping** {file_mapping}')
+ expected = [
+ [pathlib.Path('foo/bahr_travail.vhdl'), pathlib.Path('foo/bahr.vhdl').as_posix(), False, True]
+ ]
+ print(f'##file mapping## {expected}')
+ self.assertEqual(file_mapping, expected)
+ lib_mapping = self.project_creator.sigasi_project._SigasiProject__libraryMappingFileCreator._LibraryMappingFileCreator__entries
+ lib_expected = {
+ '/': 'not mapped',
+ 'foo/bahr.vhdl': 'work',
+ 'foo/bahr_travail.vhdl': 'travail',
+ 'foo/bar.v': 'work',
+ 'foo/bar.vhd': 'work',
+ 'foo/one/two/bar.vhdl': 'work',
+ 'foo/one/bar.vhd': 'work',
+ 'foo/one/bars.vhd': 'labor',
+ 'foo2/bar.vhd': 'work'
+ }
+ self.assertEqual(lib_mapping, lib_expected)
+
+ def test_get_parser_for_type(self):
+ self.assertEqual(get_parser_for_type('dotf'), DotFfileParser.DotFfileParser)
+ self.assertEqual(get_parser_for_type('csv'), CsvParser.CsvParser)
+ self.assertEqual(get_parser_for_type('hdp'), HdpParser)
+ self.assertEqual(get_parser_for_type('xise'), XilinxProjectParser)
+ self.assertEqual(get_parser_for_type('filelist'), ProjectFileParser)
+
+ @staticmethod
+ def set_up_simple_project(base_path: pathlib.Path):
+ base_path.mkdir()
+ base_path.joinpath('foo').mkdir()
+ base_path.joinpath('bar').mkdir()
+ base_path.joinpath('foo/one').mkdir()
+ base_path.joinpath('foo/one/two').mkdir()
+ base_path.joinpath('foo/bhar.v').touch()
+ base_path.joinpath('foo/bhar.vhd').touch()
+ base_path.joinpath('foo/bhar.v').touch()
+ base_path.joinpath('foo/barh.v').touch()
+ base_path.joinpath('foo/one/bar.v').touch()
+ base_path.joinpath('foo/one/two/bar.v').touch()
+ base_path.joinpath('bar/foo.vhdl').touch()
+
+ def test_create_library_mapping_folders(self):
+ base_path = pathlib.Path.cwd().joinpath('test_create_library_mapping_folders')
+ shutil.rmtree(base_path, True)
+ self.set_up_simple_project(base_path)
+ entries = {
+ base_path.joinpath('foo/bhar.v'): 'main',
+ base_path.joinpath('foo/bhar.vhd'): 'main',
+ base_path.joinpath('foo/barh.v'): 'other',
+ base_path.joinpath('foo/one/two/bar.v'): 'main',
+ base_path.joinpath('bar/foo.vhdl'): ['main', 'some']
+ }
+ self.project_creator.create_library_mapping_folders(entries, None)
+ lib_mapping = self.project_creator.sigasi_project._SigasiProject__libraryMappingFileCreator._LibraryMappingFileCreator__entries
+ lib_expected = {
+ '/': 'not mapped',
+ 'foo': 'main',
+ 'foo/barh.v': 'other',
+ 'foo/one': 'not mapped',
+ 'foo/one/two': 'main',
+ 'bar': 'main',
+ 'bar/foo_some.vhdl': 'some'
+ }
+ self.assertEqual(lib_mapping, lib_expected)
+
+ @staticmethod
+ def setup_fake_uvm_folder(uvm_path: pathlib.Path):
+ if uvm_path.exists():
+ return
+ uvm_path.mkdir()
+ uvm_path.joinpath('src').mkdir()
+ uvm_path.joinpath('src/uvm_pkg.sv').touch()
+ uvm_path.joinpath('src/uvm_macros.svh').touch()
+
+ def test_parse_and_create_project(self):
+ self.maxDiff = None
+ base_path = pathlib.Path.cwd()
+ uvm_path = base_path.joinpath('uvm').absolute()
+ self.setup_fake_uvm_folder(uvm_path)
+ command_line_options = ['the_project', 'tests/test-files/dotFparser/features.f', '-d', base_path.as_posix(),
+ '--skip-check-exists', '--layout', 'in-place', '-f', '--uvm', str(uvm_path),
+ '--uvmlib', 'uvm']
+ self.options = ProjectOptions(command_line_options)
+ self.project_creator = ProjectCreatorInPlace(self.options)
+ os.environ['SIM'] = 'simulator'
+ os.environ['FUBAR_HOME'] = 'phoo/barh/ome'
+ (the_project, verilog_defines) = self.project_creator.create_project()
+ del os.environ['SIM']
+ del os.environ['FUBAR_HOME']
+ file_mapping = \
+ self.project_creator.sigasi_project._SigasiProject__projectFileCreator._ProjectFileCreator__links
+ expected = [
+ ['include_folders', 'virtual:/virtual', True, False],
+ [pathlib.Path('include_folders/verilog'), '/somelib/verilog', True, True],
+ [pathlib.Path('Common Libraries/uvm'), '/home/wmeeus/git/SigasiProjectCreator_github/uvm/src', True, True],
+ ['Common Libraries', 'virtual:/virtual', True, False],
+ ['Common Libraries/IEEE', 'sigasiresource:/vhdl/2008/IEEE', True, False],
+ ['Common Libraries/IEEE Synopsys', 'sigasiresource:/vhdl/2008/IEEE%20Synopsys', True, False],
+ ['Common Libraries/STD', 'sigasiresource:/vhdl/2008/STD', True, False]
+ ]
+ self.assertEqual(file_mapping, expected)
+ lib_mapping = \
+ self.project_creator.sigasi_project._SigasiProject__libraryMappingFileCreator._LibraryMappingFileCreator__entries
+ lib_expected = {
+ '/': 'not mapped',
+ '': 'not mapped',
+ 'Common Libraries': 'not mapped',
+ 'Common Libraries/IEEE': 'ieee',
+ 'Common Libraries/IEEE Synopsys': 'ieee',
+ 'Common Libraries/STD': 'std',
+ 'Common Libraries/uvm/uvm_pkg.sv': 'uvm',
+ 'ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_conv.v': 'foolib',
+ 'ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b_downsizer.v': 'foolib',
+ 'ipstatic/some_protocol_converter_v2_1/hdl/verilog/foo_b2s.v': 'b2s',
+ 'ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_some_protocol_converter.v': 'work',
+ 'bd/design_1/ip/design_1_auto_pc_0/simulator/design_1_auto_pc_0.v': 'work',
+ 'bd/design_1/hdl/design_all.vhd': 'work',
+ 'tests/test-files/dotFparser/glbl.v': 'work'
+ }
+ self.assertEqual(lib_mapping, lib_expected)
+ self.assertTrue(base_path.joinpath('.project').is_file())
+ self.assertTrue(base_path.joinpath('.library_mapping.xml').is_file())
+ self.assertTrue(base_path.joinpath('.settings').is_dir())
+ expected_includes = [
+ pathlib.Path('tests/rtl/phoo/barh/ome/pkg'),
+ pathlib.Path('tests/bench/verilog'),
+ pathlib.Path('tests/verilog'),
+ pathlib.Path('include_folders/verilog'),
+ pathlib.Path('Common Libraries/uvm')
+ ]
+ expected_includes.sort()
+ actual_includes = the_project.verilog_includes
+ actual_includes.sort()
+ print(f'**includes** {expected_includes}')
+ print(f'##includes## {actual_includes}')
+ self.assertEqual(actual_includes, expected_includes)
+ expected_defines = [
+ 'SIGASI="yes"',
+ 'FOOOOOOOH'
+ ]
+ self.assertEqual(verilog_defines, expected_defines)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/ProjectFileCreatorTest.py b/tests/ProjectFileCreatorTest.py
index 163d9e2..e7b3279 100644
--- a/tests/ProjectFileCreatorTest.py
+++ b/tests/ProjectFileCreatorTest.py
@@ -5,7 +5,8 @@
"""
import unittest
-from SigasiProjectCreator.Creator import ProjectFileCreator
+from SigasiProjectCreator import VhdlVersion, VerilogVersion
+from SigasiProjectCreator.SigasiProject import ProjectFileCreator, project_location_path
from string import Template
test_template = Template('''
@@ -25,7 +26,11 @@
${natures}\t\torg.eclipse.xtext.ui.shared.xtextNature
\t
\t
-\t\t
+${vhdl_links}${extra_links}\t
+
+''')
+
+vhdl_linked_resources = '''\t\t
\t\t\tCommon Libraries
\t\t\t2
\t\t\tvirtual:/virtual
@@ -45,9 +50,7 @@
\t\t\t2
\t\t\tsigasiresource:/vhdl/93/STD
\t\t
-${extra_links}\t
-
-''')
+'''
link_template = Template('''\t\t
\t\t\t${name}
@@ -69,8 +72,9 @@ def setUp(self):
def test_tutorial_project(self):
# Vhdl nature is the default
- self.assertEqual(test_template.substitute(extra_links="", project_references="", natures=vhdl_nature),
- str(self.creator))
+ self.creator.set_languages(VhdlVersion.NINETY_THREE, None)
+ self.assertEqual(test_template.substitute(extra_links="", project_references="", natures=vhdl_nature,
+ vhdl_links = vhdl_linked_resources), str(self.creator))
def check_links(self, links, natures):
extra_links = ""
@@ -78,21 +82,36 @@ def check_links(self, links, natures):
location = "foobar/" + link
self.creator.add_link(link, location)
extra_links += link_template.substitute(name=link, file_type=1, location=location)
- expected = test_template.substitute(extra_links=extra_links, project_references="", natures=natures)
+ if vhdl_nature in natures:
+ linked_resources = vhdl_linked_resources
+ else:
+ linked_resources = ''
+ expected = test_template.substitute(extra_links=extra_links, project_references="", natures=natures,
+ vhdl_links=linked_resources)
self.assertEqual(expected, str(self.creator))
def test_one_verilog_link(self):
+ self.creator.set_languages(None, VerilogVersion.TWENTY_O_FIVE)
self.check_links(["test.sv"], verilog_nature)
def test_one_vhdl_link(self):
+ self.creator.set_languages(VhdlVersion.NINETY_THREE, None)
self.check_links(["test.vhdl"], vhdl_nature)
def test_mixed_links(self):
+ self.creator.set_languages(VhdlVersion.NINETY_THREE, VerilogVersion.TWENTY_O_FIVE)
self.check_links(["test.vhdl", "test.sv"], verilog_nature + vhdl_nature)
+ @unittest.skip # project reference is obsolete
def test_one_project_reference(self):
self.creator.add_project_reference('other_tutorial')
project_reference = '''\t\tother_tutorial\n'''
expected = test_template.substitute(extra_links="", project_references=project_reference, natures=vhdl_nature)
self.assertEqual(expected, str(self.creator))
+
+ def test_project_location_path(self):
+ self.assertEqual(project_location_path('/absolute/path'), '/absolute/path')
+ self.assertEqual(project_location_path('local/relative/path'), 'local/relative/path')
+ self.assertEqual(project_location_path('../relative/path'), 'PARENT-1-PROJECT_LOC/relative/path')
+ self.assertEqual(project_location_path('../../../../relative/path'), 'PARENT-4-PROJECT_LOC/relative/path')
diff --git a/tests/ProjectOptionsTest.py b/tests/ProjectOptionsTest.py
new file mode 100644
index 0000000..fcd2b1c
--- /dev/null
+++ b/tests/ProjectOptionsTest.py
@@ -0,0 +1,141 @@
+import pathlib
+import unittest
+
+from SigasiProjectCreator import VhdlVersion, VerilogVersion, CsvParser
+from SigasiProjectCreator.ProjectOptions import ProjectOptions, get_file_type
+
+
+class TestProjectOptions(unittest.TestCase):
+ def test_dotf_file(self):
+ self.assertEqual(get_file_type('foo/bahr/hello.f'), 'dotf')
+
+ def test_csv_file(self):
+ self.assertEqual(get_file_type('foo/rab/hello.csV'), 'csv')
+
+ def test_hdp_file(self):
+ self.assertEqual(get_file_type('foo/bahr/hello-oh.hdp'), 'hdp')
+
+ def test_file_list(self):
+ self.assertEqual(get_file_type('foo/bahr/hello.v'), 'filelist')
+
+ def test_constructor(self):
+ args_parser = ProjectOptions(['foo', 'tests/test-files/compilation_order.csv'])
+ self.assertTrue(isinstance(args_parser, ProjectOptions))
+
+ def test_parser_minimal(self):
+ options = ProjectOptions(['my_project', 'tests/test-files/compilation_order.csv'])
+ self.assertEqual(options.input_format, 'csv')
+ self.assertEqual(options.layout, 'in-place')
+ self.assertEqual(options.destination_folder, pathlib.Path.cwd())
+ self.assertFalse(options.enable_vhdl)
+ self.assertFalse(options.enable_verilog)
+ self.assertFalse(options.enable_vunit)
+ self.assertEqual(options.encoding, 'UTF-8')
+ self.assertEqual(options.vhdl_version, VhdlVersion.TWENTY_O_EIGHT)
+ self.assertEqual(options.verilog_version, str(VerilogVersion.TWENTY_O_FIVE))
+ self.assertFalse(options.force_overwrite)
+ self.assertFalse(options.skip_check_exists)
+ self.assertFalse(options.use_relative_path(pathlib.Path.cwd()))
+
+ def test_parser_many_options(self):
+ command_line_options = ['the_project', 'tests/test-files/tree/compilation_order.csv', '-d', 'tests',
+ '--layout', 'simulator',
+ # '--uvm', 'src',
+ '--use-uvm-home',
+ '--uvmlib', 'uvm_lib',
+ '--format', 'csv',
+ '--mapping', 'folder',
+ '--enable-vhdl',
+ '--vhdl-version', '2002',
+ '--enable-verilog',
+ '--verilog-as-sv',
+ '--enable-vunit',
+ '--work', 'worklib',
+ '--skip-check-exists',
+ '--encoding', 'UTF-9',
+ '--force',
+ '--rel-path', 'src'
+ ]
+ options = ProjectOptions(command_line_options)
+ self.assertEqual(options.input_format, 'csv')
+ self.assertEqual(options.layout, 'simulator')
+ self.assertEqual(options.destination_folder, pathlib.Path('tests').absolute())
+ self.assertTrue(options.enable_vhdl)
+ self.assertTrue(options.enable_verilog)
+ self.assertTrue(options.enable_vunit)
+ self.assertEqual(options.encoding, 'UTF-9')
+ self.assertEqual(options.vhdl_version, VhdlVersion.TWENTY_O_TWO)
+ self.assertEqual(options.verilog_version, str(VerilogVersion.TWENTY_TWELVE))
+ self.assertTrue(options.force_overwrite)
+ self.assertTrue(options.skip_check_exists)
+ self.assertFalse(options.use_relative_path(pathlib.Path.cwd()))
+ self.assertTrue(options.use_relative_path(pathlib.Path('src').absolute()))
+ self.assertEqual(options.uvm, pathlib.Path('ENV-UVM_HOME'))
+ self.assertEqual(options.uvm_lib, 'uvm_lib')
+ self.assertEqual(options.mapping, 'folder')
+
+ def test_parser_multiple_input_files(self):
+ command_line_options = ['the_project',
+ 'tests/test-files/dotFparser/continuation.f', 'tests/test-files/dotFparser/filelist.f']
+ options = ProjectOptions(command_line_options)
+ self.assertEqual(options.input_format, 'dotf')
+
+ def test_parser_nonexistent_single_input_file(self):
+ command_line_options = ['the_project',
+ 'notexist.f']
+ with self.assertRaises(SystemExit) as context:
+ options = ProjectOptions(command_line_options)
+ self.assertEqual('1', str(context.exception)) # exit code 1 from argparse error handling
+
+ def test_parser_nonexistent_multiple_input_files(self):
+ command_line_options = ['the_project',
+ 'continuation.f', 'tests/test-files/dotFparser/filelist.f']
+ with self.assertRaises(SystemExit) as context:
+ options = ProjectOptions(command_line_options)
+ self.assertEqual('1', str(context.exception)) # exit code 1 from argparse error handling
+
+ def test_parser_mixed_input_types(self):
+ command_line_options = ['the_project',
+ 'tests/test-files/tree/compilation_order.csv', 'tests/test-files/dotFparser/filelist.f']
+ with self.assertRaises(SystemExit) as context:
+ options = ProjectOptions(command_line_options)
+ self.assertEqual('2', str(context.exception)) # exit code 2 from argparse error handling
+
+ def test_parser_cant_create_destination_folder(self):
+ command_line_options = ['the_project', 'tests/test-files/tree/compilation_order.csv',
+ '--destination', 'phoo/bahr']
+ with self.assertRaises(SystemExit) as context:
+ options = ProjectOptions(command_line_options)
+ print(f'*ERROR* {context.exception}')
+ self.assertEqual('1', str(context.exception)) # exit code 1 from argparse error handling
+
+ def test_parser_do_create_destination_folder(self):
+ command_line_options = ['the_project', 'tests/test-files/tree/compilation_order.csv', '-d', 'phoobahr']
+ options = ProjectOptions(command_line_options)
+ destination_folder = pathlib.Path('phoobahr')
+ self.assertTrue(destination_folder.is_dir())
+ destination_folder.rmdir()
+
+ # def test_parser_parse_file(self):
+ # command_line_options = ['the_project', 'tests/test-files/tree/compilation_order.csv']
+ # options = ProjectOptions(command_line_options)
+ # options.parse_args(command_line_options)
+ # project_name, input_file, dest_folder, project_entries = options.parse_input_file(CsvParser.parse_file)
+ # self.assertEqual(project_name, 'the_project')
+ # self.assertEqual(input_file, 'tests/test-files/tree/compilation_order.csv')
+ # self.assertEqual(dest_folder, pathlib.Path.cwd().absolute())
+ # self.assertTrue(isinstance(project_entries, dict))
+ #
+ # def test_parser_parse_list(self):
+ # command_line_options = ['the_project', 'tests/test-files/tutorial/clock_generator.vhd,tests/test-files/tutorial/dut.vhd']
+ # args_parser = ProjectOptions()
+ # args_parser.parse_args(command_line_options)
+ # project_name, input_file, dest_folder, project_entries = args_parser.parse_input_file(None)
+ # self.assertEqual(project_name, 'the_project')
+ # self.assertTrue(input_file is None)
+ # self.assertEqual(dest_folder, pathlib.Path.cwd().absolute())
+ # self.assertTrue(isinstance(project_entries, dict))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/SettingsFileWriterTest.py b/tests/SettingsFileWriterTest.py
index 2ff382b..bd18dc9 100644
--- a/tests/SettingsFileWriterTest.py
+++ b/tests/SettingsFileWriterTest.py
@@ -24,24 +24,22 @@ def tearDown(self):
def test_simple_write(self):
self.path = tempfile.mktemp()
content = "some content"
- write(".", self.path, content)
+ write(".", self.path, content, True)
self.assertCorrect(self.path, content)
def test_xml_write(self):
self.path = tempfile.mktemp(suffix=".xml")
content = "test\ntest2\n"
- write(".", self.path, content)
+ write(".", self.path, content, True)
self.assertCorrect(self.path, content)
- @unittest.expectedFailure
def test_non_existent_parent_write(self):
self.path = self.prefix + "/" + self.prefix
content = "some content"
- try:
- write(".", self.path, content)
- except IOError:
- self.path = None
- raise AssertionError("Path doesn't exist")
+ with self.assertRaises(IOError) as context:
+ write(".", self.path, content, True)
+ print(f'Exception: {str(context.exception)}')
+ self.assertTrue('No such file or directory' in str(context.exception))
def test_existent_parent_write(self):
tempdir = None
@@ -49,7 +47,7 @@ def test_existent_parent_write(self):
tempdir = tempfile.mkdtemp()
self.path = tempfile.mktemp(dir=tempdir)
content = "some content"
- write(".", self.path, content)
+ write(".", self.path, content, True)
self.assertCorrect(self.path, content)
finally:
# Teardown
diff --git a/tests/SigasiProjectCreatorTest.py b/tests/SigasiProjectTest.py
similarity index 60%
rename from tests/SigasiProjectCreatorTest.py
rename to tests/SigasiProjectTest.py
index b34b926..eef1463 100644
--- a/tests/SigasiProjectCreatorTest.py
+++ b/tests/SigasiProjectTest.py
@@ -5,23 +5,26 @@
"""
import unittest
-import SigasiProjectCreator.Creator as sPC
+import SigasiProjectCreator.SigasiProject as sPC
import SigasiProjectCreator.VerilogVersion as VerilogVersion
import SigasiProjectCreator.VhdlVersion as VhdlVersion
-from SigasiProjectCreator.Creator import SigasiProjectCreator
+from SigasiProjectCreator.ProjectOptions import ProjectOptions
+from SigasiProjectCreator.SigasiProject import SigasiProject
-class SigasiProjectCreatorTest(unittest.TestCase):
+class SigasiProjectTest(unittest.TestCase):
# No teardown needed, a new creator is created every instance
def setUp(self):
- self.creator = SigasiProjectCreator('tutorial')
+ command_line_options = ['the_project', 'tests/test-files/tree/compilation_order.csv']
+ self.options = ProjectOptions(command_line_options)
+ self.creator = SigasiProject(self.options)
def test_check_hdl_versions_both_none(self):
with self.assertRaises(ValueError) as exc:
sPC.check_hdl_versions(None, None)
self.assertTrue(
- '''Only 93, 2002, 2008 is/are allowed as VHDL version number.
-Only v2005 is/are allowed as Verilog version number.''' == str(exc.exception))
+ '''Only 93, 2002, 2008, 2019 is/are allowed as VHDL version number.
+Only v2005, sv2012 is/are allowed as Verilog version number.''' == str(exc.exception))
def test_check_hdl_versions_vhdl_none(self):
sPC.check_hdl_versions(None, VerilogVersion.TWENTY_O_FIVE)
@@ -35,16 +38,16 @@ def test_check_hdl_versions_both_correct(self):
def test_check_hdl_versions_vhdl_wrong(self):
with self.assertRaises(ValueError) as exc:
sPC.check_hdl_versions(VerilogVersion.TWENTY_O_FIVE, VerilogVersion.TWENTY_O_FIVE)
- self.assertTrue("Only 93, 2002, 2008 is/are allowed as VHDL version number." == str(exc.exception))
+ self.assertTrue("Only 93, 2002, 2008, 2019 is/are allowed as VHDL version number." == str(exc.exception))
def test_check_hdl_versions_verilog_wrong(self):
with self.assertRaises(ValueError) as exc:
sPC.check_hdl_versions(VhdlVersion.NINETY_THREE, VhdlVersion.NINETY_THREE)
- self.assertTrue("Only v2005 is/are allowed as Verilog version number." == str(exc.exception))
+ self.assertTrue("Only v2005, sv2012 is/are allowed as Verilog version number." == str(exc.exception))
def test_check_hdl_versions_both_wrong(self):
with self.assertRaises(ValueError) as exc:
sPC.check_hdl_versions(VerilogVersion.TWENTY_O_FIVE, VhdlVersion.NINETY_THREE)
self.assertTrue(
- '''Only 93, 2002, 2008 is/are allowed as VHDL version number.
-Only v2005 is/are allowed as Verilog version number.''' == str(exc.exception))
+ '''Only 93, 2002, 2008, 2019 is/are allowed as VHDL version number.
+Only v2005, sv2012 is/are allowed as Verilog version number.''' == str(exc.exception))
diff --git a/tests/parseFileTest.py b/tests/parseFileTest.py
index b384405..4869b2e 100644
--- a/tests/parseFileTest.py
+++ b/tests/parseFileTest.py
@@ -107,8 +107,8 @@ def test_wildcard(self):
'-maxdelays',
'-sdf_cmd_file',
'./sdf_cmd.cmd',
- '/usr/eda/dk/vendor/tech/verilog/*.v',
- '../../synthesis/image_average.v',
+ '../tutorial/*.vhd',
+ '/absolute/path/synthesis/image_average.v',
'../tb/tb_image.vhd',
'../../rtl/image_ram.vhd'
]
diff --git a/tests/test-files/dotFparser/features.f b/tests/test-files/dotFparser/features.f
new file mode 100644
index 0000000..c031559
--- /dev/null
+++ b/tests/test-files/dotFparser/features.f
@@ -0,0 +1,33 @@
+////////////////////////////////////////////////////////////////////////////////
+// Comments //
+////////////////////////////////////////////////////////////////////////////////
+
+-makelib foolib -sv \
+ ../../../ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_conv.v
+ ../../../ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_b_downsizer.v
+-endlib
+-makelib ies_lib/b2s -sv \
+ ../../../ipstatic/some_protocol_converter_v2_1/hdl/verilog/foo_b2s.v
+-endlib
+../../../ipstatic/some_protocol_converter_v2_1/hdl/verilog/some_protocol_converter_v2_1_some_protocol_converter.v
+../../../bd/design_1/ip/design_1_auto_pc_0/$(SIM)/design_1_auto_pc_0.v
+../../../bd/design_1/hdl/design_all.vhd
+
+-smartorder -work work -V93 -top tb_image -gui -access +rw -maxdelays -sdf_cmd_file ./sdf_cmd.cmd
+glbl.v
+/*
+ * Block comments
+ * More comments
+ */
+
++incdir+../../rtl/$FUBAR_HOME/pkg/
+
+//=============================================================================
+// Intermediate comments
+//=============================================================================
+
++incdir+../../bench/verilog/
++incdir+../../verilog/
++incdir+/somelib/verilog/
++define+SIGASI="yes"
++define+FOOOOOOOH
diff --git a/tests/test-files/dotFparser/wildcard.f b/tests/test-files/dotFparser/wildcard.f
index ac6f4de..06723cd 100644
--- a/tests/test-files/dotFparser/wildcard.f
+++ b/tests/test-files/dotFparser/wildcard.f
@@ -1,5 +1,5 @@
-smartorder -work work -V93 -top tb_image -gui -access +rw -maxdelays -sdf_cmd_file ./sdf_cmd.cmd
-/usr/eda/dk/vendor/tech/verilog/*.v
-../../synthesis/image_average.v
+../tutorial/*.vhd
+/absolute/path/synthesis/image_average.v
../tb/tb_image.vhd
../../rtl/image_ram.vhd