litex/litex/build: adding argument_parser (LiteXArgumentParser) to factorize toolchain aspects and common args
This commit is contained in:
parent
d061e9b9cf
commit
ad7ded9358
|
@ -0,0 +1,194 @@
|
||||||
|
#
|
||||||
|
# This file is part of LiteX.
|
||||||
|
#
|
||||||
|
# This file is Copyright (c) 2022 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from litex.soc.integration.soc_core import *
|
||||||
|
from litex.soc.integration.builder import *
|
||||||
|
|
||||||
|
# LitexArgumentParser ------------------------------------------------------------------------------
|
||||||
|
class LiteXArgumentParser(argparse.ArgumentParser):
|
||||||
|
"""
|
||||||
|
ArgumentParser subclass used to intercept parse_args call and to simplify
|
||||||
|
common arguments addition
|
||||||
|
Attributes
|
||||||
|
==========
|
||||||
|
_platform: GenericPlatform subclass
|
||||||
|
target platform
|
||||||
|
_device: str
|
||||||
|
target device family
|
||||||
|
_args: argparse.Namespace
|
||||||
|
list of args after parse_args call
|
||||||
|
_toolchain: str
|
||||||
|
toolchain used at build time
|
||||||
|
_default_toolchain: str
|
||||||
|
toolchain to use by default or when no selection is done by the user
|
||||||
|
"""
|
||||||
|
def __init__(self, platform=None, **kwargs):
|
||||||
|
"""
|
||||||
|
CTOR: create a Target options group, adds toolchain, build and load
|
||||||
|
arguments. Call builder_args and soc_core_args for fill parser with
|
||||||
|
corresponding options
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
==========
|
||||||
|
platform: GenericPlatform subclass
|
||||||
|
targeted platform
|
||||||
|
kwargs: dict
|
||||||
|
all arguments passed to argparse.ArgumentParser CTOR
|
||||||
|
"""
|
||||||
|
argparse.ArgumentParser.__init__(self, kwargs)
|
||||||
|
self._platform = platform
|
||||||
|
if platform is not None:
|
||||||
|
self._device = platform.device_family
|
||||||
|
toolchains = platform.toolchains(self._device)
|
||||||
|
self._default_toolchain = toolchains[0]
|
||||||
|
else:
|
||||||
|
self._device = None
|
||||||
|
toolchains = None
|
||||||
|
self._default_toolchain = None
|
||||||
|
self._args = None
|
||||||
|
self._toolchain = None
|
||||||
|
|
||||||
|
self._target_group = self.add_argument_group(title="Target options")
|
||||||
|
if toolchains is not None:
|
||||||
|
self.add_target_argument("--toolchain",
|
||||||
|
default=self._default_toolchain,
|
||||||
|
choices=toolchains,
|
||||||
|
help="FPGA toolchain ({}).".format(" or ".join(toolchains)))
|
||||||
|
else:
|
||||||
|
self.add_target_argument("-toolchain", help="FPGA toolchain")
|
||||||
|
self.add_target_argument("--build", action="store_true", help="Build design.")
|
||||||
|
self.add_target_argument("--load", action="store_true", help="Load bitstream.")
|
||||||
|
builder_args(self)
|
||||||
|
soc_core_args(self)
|
||||||
|
|
||||||
|
def set_platform(self, platform):
|
||||||
|
""" set platform. Check first if not already set
|
||||||
|
|
||||||
|
Parameter
|
||||||
|
=========
|
||||||
|
platform: GenericPlatform subclass
|
||||||
|
the platform
|
||||||
|
"""
|
||||||
|
assert self._platform is None
|
||||||
|
self._platform = platform
|
||||||
|
self._device = platform.device_family
|
||||||
|
toolchains = platform.toolchains(self._device)
|
||||||
|
self._default_toolchain = toolchains[0]
|
||||||
|
# add a setter (LitexArgumentParserInstance.platform = myPlatform)
|
||||||
|
platform = property(None, set_platform)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def target_group(self):
|
||||||
|
""" return target_group
|
||||||
|
"""
|
||||||
|
return self._target_group
|
||||||
|
|
||||||
|
def add_target_argument(self, *args, **kwargs):
|
||||||
|
""" wrapper to add argument to "Target options group" from outer of this
|
||||||
|
class
|
||||||
|
"""
|
||||||
|
self._target_group.add_argument(*args, **kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def builder_argdict(self):
|
||||||
|
"""
|
||||||
|
access to builder_argdict
|
||||||
|
|
||||||
|
Return
|
||||||
|
======
|
||||||
|
builder arguments dict
|
||||||
|
"""
|
||||||
|
return builder_argdict(self._args)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def soc_core_argdict(self):
|
||||||
|
"""
|
||||||
|
access to soc_core_argdict
|
||||||
|
|
||||||
|
Return
|
||||||
|
======
|
||||||
|
soc_core arguments dict
|
||||||
|
"""
|
||||||
|
return soc_core_argdict(self._args)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def toolchain_argdict(self):
|
||||||
|
"""
|
||||||
|
access to target toolchain argdict
|
||||||
|
|
||||||
|
Return
|
||||||
|
======
|
||||||
|
toolchain arguments dict
|
||||||
|
"""
|
||||||
|
if self._platform is None:
|
||||||
|
return dict()
|
||||||
|
else:
|
||||||
|
return self._platform.get_argdict(self._toolchain, self._args)
|
||||||
|
|
||||||
|
def parse_args(self, args=None, namespace=None):
|
||||||
|
"""
|
||||||
|
override argparse.ArgumentParser.parse_args to inject toolchain
|
||||||
|
and soc_core args.
|
||||||
|
Checks first is platform is set: when platform is none: try to
|
||||||
|
search for a platform argument
|
||||||
|
"""
|
||||||
|
# When platform is None try to search for a user input
|
||||||
|
if self._platform is None:
|
||||||
|
platform = self.get_value_from_key("--platform", None)
|
||||||
|
if platform is not None:
|
||||||
|
self.set_platform(importlib.import_module(platform).Platform)
|
||||||
|
|
||||||
|
# Intercept selected toolchain to fill arguments.
|
||||||
|
if self._platform is not None:
|
||||||
|
self._toolchain = self.get_value_from_key("--toolchain",
|
||||||
|
self._default_toolchain)
|
||||||
|
if self._toolchain is not None:
|
||||||
|
self._platform.fill_args(self._toolchain, self)
|
||||||
|
|
||||||
|
# Intercept selected CPU to fill arguments.
|
||||||
|
cpu_cls = None
|
||||||
|
cpu_name = self.get_value_from_key("--cpu-type")
|
||||||
|
if cpu_name is not None:
|
||||||
|
cpu_cls = cpu.CPUS[cpu_name]
|
||||||
|
if cpu_cls is not None and hasattr(cpu_cls, "args_fill"):
|
||||||
|
cpu_cls.args_fill(self)
|
||||||
|
self._args = argparse.ArgumentParser.parse_args(self, args, namespace)
|
||||||
|
|
||||||
|
# Re-inject CPU read arguments.
|
||||||
|
if cpu_cls is not None and hasattr(cpu_cls, "args_read"):
|
||||||
|
cpu_cls.args_read(args)
|
||||||
|
|
||||||
|
return self._args
|
||||||
|
|
||||||
|
def get_value_from_key(self, key, default=None):
|
||||||
|
"""
|
||||||
|
search key into sys.argv
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
==========
|
||||||
|
key: str
|
||||||
|
key to search
|
||||||
|
default: str
|
||||||
|
default value when key is not in sys.argv
|
||||||
|
|
||||||
|
Return
|
||||||
|
======
|
||||||
|
sys.argv corresponding value or default
|
||||||
|
"""
|
||||||
|
value = None
|
||||||
|
try:
|
||||||
|
index = [i for i, item in enumerate(sys.argv) if key in item][0]
|
||||||
|
if '=' in sys.argv[index]:
|
||||||
|
value = sys.argv[index].split('=')[1]
|
||||||
|
else:
|
||||||
|
value = sys.argv[index+1]
|
||||||
|
except IndexError:
|
||||||
|
value = default
|
||||||
|
return value
|
Loading…
Reference in New Issue