Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ot] scripts/opentitan: cfggen.py: define a list of supported tops #117

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 24 additions & 23 deletions docs/opentitan/cfggen.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,38 @@ the QEMU binary.
## Usage

````text
usage: cfggen.py [-h] [-o CFG] [-T TOP] [-c SV] [-l SV] [-t HJSON] [-s SOCID]
[-C COUNT] [-v] [-d]
TOPDIR
usage: cfggen.py [-h] [-T {darjeeling,earlgrey}] [-o CFG] [-c SV] [-l SV]
[-t HJSON] [-s SOCID] [-C COUNT] [-v] [-d]
[OTDIR]

OpenTitan QEMU configuration file generator.

options:
-h, --help show this help message and exit

Files:
TOPDIR OpenTitan top directory
-o CFG, --out CFG Filename of the config file to generate
-T TOP, --top TOP OpenTitan Top name (default: darjeeling)
-c SV, --otpconst SV OTP Constant SV file (default: auto)
-l SV, --lifecycle SV
LifeCycle SV file (default: auto)
-t HJSON, --topcfg HJSON
OpenTitan top HJSON config file (default: auto)
OTDIR OpenTitan root directory
-T, --top {darjeeling,earlgrey}
OpenTitan top name
-o, --out CFG Filename of the config file to generate
-c, --otpconst SV OTP Constant SV file (default: auto)
-l, --lifecycle SV LifeCycle SV file (default: auto)
-t, --topcfg HJSON OpenTitan top HJSON config file (default: auto)

Modifiers:
-s SOCID, --socid SOCID
SoC identifier, if any
-C COUNT, --count COUNT
SoC count (default: 1)
-s, --socid SOCID SoC identifier, if any
-C, --count COUNT SoC count (default: 1)

Extras:
-v, --verbose increase verbosity
-d, --debug enable debug mode
````


### Arguments

`TOPDIR` is a required positional argument which should point to the top-level directory of the
OpenTitan repository to analyze. It is used to generate the path towards the required files to
parse, each of which can be overidden with options `-c`, `-l` and `-t`.
`OTDIR` is a required positional argument which should point to the root directory of the OpenTitan
repository to analyze. It is used to generate the path towards the required files to parse, each of
which can be overidden with options `-c`, `-l` and `-t`.

* `-C` specify how many SoCs are used on the platform

Expand All @@ -61,16 +57,21 @@ parse, each of which can be overidden with options `-c`, `-l` and `-t`.

* `-s` specify a SoC identifier for OT platforms with mulitple SoCs

* `-T` specify the OpenTitan _top_ name, such as `Darjeeling`, `EarlGrey`, ... This option is
case-insensitive.
* `-T` specify the OpenTitan _top_ name, such as `darjeeling`, `earlgrey`, ... This option is
mandatory if `-t` is not specified. An OTDIR root directory should be specified with this option.

* `-t` alternative path to the `top_<top>.gen.hjson` file
* `-t` path to the `top_<top>.gen.hjson` file. This option is mandatory is `-T` is not specified.

* `-v` can be repeated to increase verbosity of the script, mostly for debug purpose.


### Examples

````sh
./scripts/opentitan/cfggen.py ../opentitan-integrated -o opentitan.cfg
./scripts/opentitan/cfggen.py ../opentitan -T earlgrey -o opentitan.cfg
````

````sh
./scripts/opentitan/cfggen.py -o opentitan.cfg \
-t ../opentitan/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
````
91 changes: 66 additions & 25 deletions scripts/opentitan/cfggen.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3

# Copyright (c) 2024 Rivos, Inc.
# Copyright (c) 2025 lowRISC contributors.
# SPDX-License-Identifier: Apache2

"""OpenTitan QEMU configuration file generator.
Expand All @@ -11,7 +12,7 @@
from argparse import ArgumentParser
from configparser import ConfigParser
from logging import getLogger
from os.path import dirname, isdir, isfile, join as joinpath, normpath
from os.path import abspath, dirname, isdir, isfile, join as joinpath, normpath
from traceback import format_exc
from typing import Optional
import re
Expand Down Expand Up @@ -52,12 +53,19 @@ def __init__(self):
self._roms: dict[Optional[int], dict[str, str]] = {}
self._otp: dict[str, str] = {}
self._lc: dict[str, str] = {}
self._top_name: Optional[str] = None

@property
def top_name(self) -> Optional[str]:
"""Return the name of the top as defined in a configuration file."""
return self._top_name

def load_top_config(self, toppath: str) -> None:
"""Load data from HJSON top configuration file."""
assert not _HJSON_ERROR
with open(toppath, 'rt') as tfp:
cfg = hjload(tfp)
self._top_name = cfg.get('name')
for module in cfg.get('module') or []:
modtype = module.get('type')
if modtype == 'rom_ctrl':
Expand Down Expand Up @@ -223,17 +231,20 @@ def _generate_life_cycle(self, cfg: ConfigParser,
def main():
"""Main routine"""
debug = True
default_top = 'Darjeeling'
top_map = {
'darjeeling': 'dj',
'earlgrey': 'eg',
}
jwnrt marked this conversation as resolved.
Show resolved Hide resolved
try:
desc = sys.modules[__name__].__doc__.split('.', 1)[0].strip()
argparser = ArgumentParser(description=f'{desc}.')
files = argparser.add_argument_group(title='Files')
files.add_argument('opentitan', nargs=1, metavar='TOPDIR',
help='OpenTitan top directory')
files.add_argument('opentitan', nargs='?', metavar='OTDIR',
help='OpenTitan root directory')
files.add_argument('-T', '--top', choices=top_map.keys(),
help='OpenTitan top name')
files.add_argument('-o', '--out', metavar='CFG',
help='Filename of the config file to generate')
files.add_argument('-T', '--top', default=default_top,
help=f'OpenTitan Top name (default: {default_top})')
files.add_argument('-c', '--otpconst', metavar='SV',
help='OTP Constant SV file (default: auto)')
files.add_argument('-l', '--lifecycle', metavar='SV',
Expand All @@ -254,29 +265,60 @@ def main():
args = argparser.parse_args()
debug = args.debug

configure_loggers(args.verbose, 'cfggen', 'otp')
log = configure_loggers(args.verbose, 'cfggen', 'otp')[0]

if _HJSON_ERROR:
argparser.error('Missing HJSON module: {_HJSON_ERROR}')

topdir = args.opentitan[0]
if not isdir(topdir):
argparser.error('Invalid OpenTitan top directory')
ot_dir = normpath(topdir)
top = f'top_{args.top.lower()}'
if args.top.lower() != default_top.lower():
var = ''.join(w[0]
for w in camel_to_snake_case(args.top).split('_'))
else:
var = 'dj'
cfg = OtConfiguration()

if not args.topcfg:
cfgpath = joinpath(ot_dir, f'hw/{top}/data/autogen/{top}.gen.hjson')
topcfg = args.topcfg
ot_dir = args.opentitan
if not topcfg:
if not args.opentitan:
argparser.error('OTDIR is required is no top file is specified')
if not isdir(ot_dir):
argparser.error('Invalid OpenTitan root directory')
ot_dir = abspath(ot_dir)
if not args.top:
argparser.error('Top name is required if no top file is '
'specified')
top = f'top_{args.top}'
topvar = top_map[args.top]
topcfg = joinpath(ot_dir, f'hw/{top}/data/autogen/{top}.gen.hjson')
if not isfile(topcfg):
argparser.error(f"No such file '{topcfg}'")
log.info("Top config: '%s'", topcfg)
cfg.load_top_config(topcfg)
else:
cfgpath = args.topcfg
if not isfile(cfgpath):
argparser.error(f"No such file '{cfgpath}'")

if not isfile(topcfg):
argparser.error(f'No such top file: {topcfg}')
cfg.load_top_config(topcfg)
ltop = cfg.top_name
if not ltop:
argparser.error('Unknown top name')
log.info("Top: '%s'", cfg.top_name)
ltop = ltop.lower()
topvar = {k.lower(): v for k, v in top_map.items()}.get(ltop)
if not topvar:
argparser.error(f'Unsupported top name: {cfg.top_name}')
top = f'top_{ltop}'
if not ot_dir:
check_dir = f'hw/{top}/data'
cur_dir = dirname(topcfg)
while cur_dir:
check_path = joinpath(cur_dir, check_dir)
if isdir(check_path):
ot_dir = cur_dir
break
cur_dir = dirname(cur_dir)
if not ot_dir:
argparser.error('Cannot find OT root directory')
elif not isdir(ot_dir):
argparser.error('Invalid OpenTitan root directory')
ot_dir = abspath(ot_dir)
log.info("OT directory: '%s'", ot_dir)
log.info("Variant: '%s'", topvar)
if not args.lifecycle:
lcpath = joinpath(ot_dir, 'hw/ip/lc_ctrl/rtl/lc_ctrl_state_pkg.sv')
else:
Expand All @@ -293,10 +335,9 @@ def main():
argparser.error(f"No such file '{ocpath}'")

cfg = OtConfiguration()
cfg.load_top_config(cfgpath)
cfg.load_lifecycle(lcpath)
cfg.load_otp_constants(ocpath)
cfg.save(var, args.socid, args.count, args.out)
cfg.save(topvar, args.socid, args.count, args.out)

except (IOError, ValueError, ImportError) as exc:
print(f'\nError: {exc}', file=sys.stderr)
Expand Down
Loading