206 lines
7.4 KiB
Python
206 lines
7.4 KiB
Python
import argparse
|
|
import os
|
|
import time
|
|
import logging
|
|
from itertools import chain
|
|
|
|
logging_map = {
|
|
"DEBUG": logging.DEBUG,
|
|
"INFO": logging.INFO,
|
|
"WARNING": logging.WARNING,
|
|
"ERROR": logging.ERROR,
|
|
"CRITICAL": logging.CRITICAL,
|
|
"NONE": logging.NOTSET
|
|
}
|
|
|
|
class CliArguments():
|
|
# TODO: Add option to remove timestamp (for SCM)
|
|
|
|
def __init__(self):
|
|
self.parser = argparse.ArgumentParser(
|
|
description="A SystemRDL 2.0 to (synthesizable) SystemVerilog compiler",
|
|
epilog="Report bugs via https://github.com/Silicon1602/srdl2sv/issues")
|
|
|
|
self.parser.add_argument(
|
|
"-a",
|
|
"--address-width",
|
|
default=32,
|
|
type=int,
|
|
help="Set the address width of the register space. For some \
|
|
protocols, the default as described in the specification \
|
|
is used. (default: %(default)s)")
|
|
|
|
self.parser.add_argument(
|
|
"-b",
|
|
"--bus",
|
|
choices=['simple', 'amba3ahblite'],
|
|
default='amba3ahblite',
|
|
help="Set the bus protocol that shall be used by software to \
|
|
communicate with the registers. If just a simple interface \
|
|
to the registers is needed, use the 'simple' protocol. \
|
|
(default: %(default)s)")
|
|
|
|
self.parser.add_argument(
|
|
"-c",
|
|
"--descriptions",
|
|
type=int,
|
|
default=0,
|
|
help="Include descriptions of addrmaps (+16), regfiles (+8), memories (+4) \
|
|
registers (+2), and fields (+1) in RTL. This is a bitfield.")
|
|
|
|
self.parser.add_argument(
|
|
"-d",
|
|
"--search-paths",
|
|
type=str,
|
|
nargs="+",
|
|
help="Point to one (or more) directories that will\
|
|
be searched for RDL files.")
|
|
|
|
self.parser.add_argument(
|
|
"-e",
|
|
"--no-enums",
|
|
action="store_true",
|
|
help="Disable enumeration generation. This will prevent the\
|
|
compiler from generating packages and it will prevent\
|
|
it from using enums in the port list.")
|
|
|
|
self.parser.add_argument(
|
|
"--file-logging",
|
|
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'NONE'],
|
|
default='NONE',
|
|
help="Set verbosity level of output to log-file. When set to 'NONE',\
|
|
nothing will be printed to the shell. (default: %(default)s)")
|
|
|
|
self.parser.add_argument(
|
|
"--stdout-logging",
|
|
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'NONE'],
|
|
default='INFO',
|
|
help="Set verbosity level of output to shell. When set to 'NONE',\
|
|
nothing will be printed to the shell. (default: %(default)s)")
|
|
|
|
self.parser.add_argument(
|
|
"--no-byte-enable",
|
|
action="store_true",
|
|
help="If this flag gets set, byte-enables get disabled. At that point, it \
|
|
is only possible to address whole registers, not single bytes within \
|
|
these registers anymore.")
|
|
|
|
self.parser.add_argument(
|
|
"-o",
|
|
"--out-dir",
|
|
type=str,
|
|
default="./srdl2sv_out",
|
|
help="Define output directory to dump files.\
|
|
If directory is non-existent, it will be created.\
|
|
(default: %(default)s)")
|
|
|
|
self.parser.add_argument(
|
|
"-r",
|
|
"--recursive-search",
|
|
action="store_true",
|
|
help="If set, the dependency directories will be\
|
|
searched recursively.")
|
|
|
|
self.parser.add_argument(
|
|
"--real-tabs",
|
|
action="store_true",
|
|
help="Use tabs, rather than spaces, for tabs")
|
|
|
|
self.parser.add_argument(
|
|
"--tab-width",
|
|
type=int,
|
|
default=4,
|
|
help="Define how many tabs or spaces will be contained\
|
|
in one level of indentation. (default: %(default)s)")
|
|
|
|
self.parser.add_argument(
|
|
"RDL",
|
|
type=str,
|
|
nargs="+",
|
|
help="Location of RDL file(s) with root addrmap.")
|
|
|
|
def get_config(self) -> dict():
|
|
args = self.parser.parse_args()
|
|
|
|
# Create dictionary to save config in
|
|
config = dict()
|
|
config['list_args'] = []
|
|
|
|
# Save input file and output directory to dump everything in
|
|
config['input_file'] = args.RDL
|
|
config['output_dir'] = args.out_dir
|
|
config['list_args'].append(f"Ouput Directory : {config['output_dir']}")
|
|
|
|
# Create output directory
|
|
try:
|
|
os.makedirs(config['output_dir'])
|
|
except FileExistsError:
|
|
pass
|
|
|
|
# Map logging level string to integers
|
|
config['stdout_log_level'] = logging_map[args.stdout_logging]
|
|
config['file_log_level'] = logging_map[args.file_logging]
|
|
config['list_args'].append(f"Stream Log Level : {args.stdout_logging}")
|
|
config['list_args'].append(f"File Log Level : {args.file_logging}")
|
|
|
|
# Determine paths to be passed to systemrdl-compiler to search
|
|
# for include files.
|
|
if args.recursive_search:
|
|
config['search_paths'] = [x[0] for y in args.search_paths for x in os.walk(y)]
|
|
else:
|
|
config['search_paths'] = args.search_paths
|
|
|
|
if not config['search_paths']:
|
|
config['search_paths'] = []
|
|
|
|
# Save timestamp, so that it can be used across the compiler
|
|
config['ts'] = time.localtime()
|
|
|
|
# Determine name of file to hold logs
|
|
ts = time.strftime('%Y%m%d_%H%M%S', config['ts'])
|
|
config['file_log_location'] = "/".join([config['output_dir'], f"srdl2sv_{ts}.log"])
|
|
|
|
# Tab style
|
|
config['real_tabs'] = args.real_tabs
|
|
config['tab_width'] = args.tab_width
|
|
|
|
config['list_args'].append(f"Use Real Tabs : {config['real_tabs']}")
|
|
config['list_args'].append(f"Tab Width : {config['tab_width']}")
|
|
|
|
# Set enums
|
|
config['enums'] = not args.no_enums
|
|
config['list_args'].append(f"Enums Enabled : {config['enums']}")
|
|
|
|
# Set bus
|
|
config['bus'] = args.bus
|
|
config['list_args'].append(f"Register Bus Type: {config['bus']}")
|
|
|
|
# Address width
|
|
if args.bus == 'amba3ahblite':
|
|
config['addrwidth'] = 32
|
|
config['addrwidth_bus_spec'] = True
|
|
else:
|
|
config['addrwidth'] = args.address_width
|
|
config['addrwidth_bus_spec'] = False
|
|
|
|
config['list_args'].append(f"Address width : {config['addrwidth']}")
|
|
|
|
# Byte enables?
|
|
config['no_byte_enable'] = args.no_byte_enable
|
|
config['list_args'].append(f"Byte enables : {not config['no_byte_enable']}")
|
|
|
|
# Set location where descirptions shall be set
|
|
# Comparison to 1 to get a Python bool
|
|
config['descriptions'] = {}
|
|
config['descriptions']['AddrMap'] = (args.descriptions >> 4) & 1 == 1
|
|
config['descriptions']['RegFile'] = (args.descriptions >> 3) & 1 == 1
|
|
config['descriptions']['Memory'] = (args.descriptions >> 2) & 1 == 1
|
|
config['descriptions']['Register'] = (args.descriptions >> 1) & 1 == 1
|
|
config['descriptions']['Field'] = (args.descriptions >> 0) & 1 == 1
|
|
config['list_args'].append(f"Descriptions : {config['descriptions']}")
|
|
|
|
# Set version
|
|
config['version'] = '0.01'
|
|
|
|
return config
|