blob: e17ff7b4532f693686d2059e4e4f3503199a7764 [file] [log] [blame]
Torsten Rasmussen8dc3f852022-09-14 22:23:15 +02001#!/usr/bin/env python3
2
3# Copyright (c) 2023 Nordic Semiconductor ASA
4# SPDX-License-Identifier: Apache-2.0
5
6import argparse
7from dataclasses import dataclass
8from pathlib import Path, PurePath
9import pykwalify.core
10import sys
11from typing import List
12import yaml
13
14
15SOC_SCHEMA_PATH = str(Path(__file__).parent / 'schemas' / 'soc-schema.yml')
16with open(SOC_SCHEMA_PATH, 'r') as f:
17 soc_schema = yaml.safe_load(f.read())
18
19ARCH_SCHEMA_PATH = str(Path(__file__).parent / 'schemas' / 'arch-schema.yml')
20with open(ARCH_SCHEMA_PATH, 'r') as f:
21 arch_schema = yaml.safe_load(f.read())
22
23SOC_YML = 'soc.yml'
24ARCHS_YML_PATH = PurePath('arch/archs.yml')
25
26class Systems:
27
28 def __init__(self, folder='', soc_yaml=None):
29 self._socs = []
30 self._series = []
31 self._families = []
32
33 if soc_yaml is None:
34 return
35
36 try:
37 data = yaml.safe_load(soc_yaml)
38 pykwalify.core.Core(source_data=data,
39 schema_data=soc_schema).validate()
40 except (yaml.YAMLError, pykwalify.errors.SchemaError) as e:
41 sys.exit(f'ERROR: Malformed yaml {soc_yaml.as_posix()}', e)
42
43 for f in data.get('family', []):
44 family = Family(f['name'], folder, [], [])
45 for s in f.get('series', []):
46 series = Series(s['name'], folder, f['name'], [])
47 socs = [(Soc(soc['name'],
48 [c['name'] for c in soc.get('cpuclusters', [])],
49 folder, s['name'], f['name']))
50 for soc in s.get('socs', [])]
51 series.socs.extend(socs)
52 self._series.append(series)
53 self._socs.extend(socs)
54 family.series.append(series)
55 family.socs.extend(socs)
56 socs = [(Soc(soc['name'],
57 [c['name'] for c in soc.get('cpuclusters', [])],
58 folder, None, f['name']))
59 for soc in f.get('socs', [])]
60 self._socs.extend(socs)
61 self._families.append(family)
62
63 for s in data.get('series', []):
64 series = Series(s['name'], folder, '', [])
65 socs = [(Soc(soc['name'],
66 [c['name'] for c in soc.get('cpuclusters', [])],
67 folder, s['name'], ''))
68 for soc in s.get('socs', [])]
69 series.socs.extend(socs)
70 self._series.append(series)
71 self._socs.extend(socs)
72
73 socs = [(Soc(soc['name'],
74 [c['name'] for c in soc.get('cpuclusters', [])],
75 folder, '', ''))
76 for soc in data.get('socs', [])]
77 self._socs.extend(socs)
78
79 @staticmethod
80 def from_file(socs_file):
81 '''Load SoCs from a soc.yml file.
82 '''
83 try:
84 with open(socs_file, 'r') as f:
85 socs_yaml = f.read()
86 except FileNotFoundError as e:
87 sys.exit(f'ERROR: socs.yml file not found: {socs_file.as_posix()}', e)
88
89 return Systems(str(socs_file.parent), socs_yaml)
90
91 @staticmethod
92 def from_yaml(socs_yaml):
93 '''Load socs from a string with YAML contents.
94 '''
95 return Systems('', socs_yaml)
96
97 def extend(self, systems):
98 self._families.extend(systems.get_families())
99 self._series.extend(systems.get_series())
100 self._socs.extend(systems.get_socs())
101
102 def get_families(self):
103 return self._families
104
105 def get_series(self):
106 return self._series
107
108 def get_socs(self):
109 return self._socs
110
111 def get_soc(self, name):
112 try:
113 return next(s for s in self._socs if s.name == name)
114 except StopIteration:
115 sys.exit(f"ERROR: SoC '{name}' is not found, please ensure that the SoC exists "
116 f"and that soc-root containing '{name}' has been correctly defined.")
117
118
119@dataclass
120class Soc:
121 name: str
122 cpuclusters: List[str]
123 folder: str
124 series: str = ''
125 family: str = ''
126
127
128@dataclass
129class Series:
130 name: str
131 folder: str
132 family: str
133 socs: List[Soc]
134
135
136@dataclass
137class Family:
138 name: str
139 folder: str
140 series: List[Series]
141 socs: List[Soc]
142
143
144def find_v2_archs(args):
145 ret = {'archs': []}
146 for root in args.arch_roots:
147 archs_yml = root / ARCHS_YML_PATH
148
149 if Path(archs_yml).is_file():
150 with Path(archs_yml).open('r') as f:
151 archs = yaml.safe_load(f.read())
152
153 try:
154 pykwalify.core.Core(source_data=archs, schema_data=arch_schema).validate()
155 except pykwalify.errors.SchemaError as e:
156 sys.exit('ERROR: Malformed "build" section in file: {}\n{}'
157 .format(archs_yml.as_posix(), e))
158
159 if args.arch is not None:
160 archs = {'archs': list(filter(
161 lambda arch: arch.get('name') == args.arch, archs['archs']))}
162 for arch in archs['archs']:
163 arch.update({'path': root / 'arch' / arch['path']})
164 arch.update({'hwm': 'v2'})
165 arch.update({'type': 'arch'})
166
167 ret['archs'].extend(archs['archs'])
168
169 return ret
170
171
172def find_v2_systems(args):
173 yml_files = []
174 systems = Systems()
175 for root in args.soc_roots:
Marc Herbert251f52c2024-03-12 23:08:40 +0000176 yml_files.extend(sorted((root / 'soc').rglob(SOC_YML)))
Torsten Rasmussen8dc3f852022-09-14 22:23:15 +0200177
178 for soc_yml in yml_files:
179 if soc_yml.is_file():
180 systems.extend(Systems.from_file(soc_yml))
181
182 return systems
183
184
185def parse_args():
186 parser = argparse.ArgumentParser(allow_abbrev=False)
187 add_args(parser)
188 return parser.parse_args()
189
190
191def add_args(parser):
192 default_fmt = '{name}'
193
194 parser.add_argument("--soc-root", dest='soc_roots', default=[],
195 type=Path, action='append',
196 help='add a SoC root, may be given more than once')
197 parser.add_argument("--soc", default=None, help='lookup the specific soc')
198 parser.add_argument("--soc-series", default=None, help='lookup the specific soc series')
199 parser.add_argument("--soc-family", default=None, help='lookup the specific family')
200 parser.add_argument("--socs", action='store_true', help='lookup all socs')
201 parser.add_argument("--arch-root", dest='arch_roots', default=[],
202 type=Path, action='append',
203 help='add a arch root, may be given more than once')
204 parser.add_argument("--arch", default=None, help='lookup the specific arch')
205 parser.add_argument("--archs", action='store_true', help='lookup all archs')
206 parser.add_argument("--format", default=default_fmt,
207 help='''Format string to use to list each soc.''')
208 parser.add_argument("--cmakeformat", default=None,
209 help='''CMake format string to use to list each arch/soc.''')
210
211
212def dump_v2_archs(args):
213 archs = find_v2_archs(args)
214
215 for arch in archs['archs']:
216 if args.cmakeformat is not None:
217 info = args.cmakeformat.format(
218 TYPE='TYPE;' + arch['type'],
219 NAME='NAME;' + arch['name'],
220 DIR='DIR;' + str(arch['path'].as_posix()),
221 HWM='HWM;' + arch['hwm'],
222 # Below is non exising for arch but is defined here to support
223 # common formatting string.
224 SERIES='',
225 FAMILY='',
226 ARCH='',
227 VENDOR=''
228 )
229 else:
230 info = args.format.format(
231 type=arch.get('type'),
232 name=arch.get('name'),
233 dir=arch.get('path'),
234 hwm=arch.get('hwm'),
235 # Below is non exising for arch but is defined here to support
236 # common formatting string.
237 series='',
238 family='',
239 arch='',
240 vendor=''
241 )
242
243 print(info)
244
245
246def dump_v2_system(args, type, system):
247 if args.cmakeformat is not None:
248 info = args.cmakeformat.format(
249 TYPE='TYPE;' + type,
250 NAME='NAME;' + system.name,
251 DIR='DIR;' + Path(system.folder).as_posix(),
252 HWM='HWM;' + 'v2'
253 )
254 else:
255 info = args.format.format(
256 type=type,
257 name=system.name,
258 dir=system.folder,
259 hwm='v2'
260 )
261
262 print(info)
263
264
265def dump_v2_systems(args):
266 systems = find_v2_systems(args)
267
268 for f in systems.get_families():
269 dump_v2_system(args, 'family', f)
270
271 for s in systems.get_series():
272 dump_v2_system(args, 'series', s)
273
274 for s in systems.get_socs():
275 dump_v2_system(args, 'soc', s)
276
277
278if __name__ == '__main__':
279 args = parse_args()
280 if any([args.socs, args.soc, args.soc_series, args.soc_family]):
281 dump_v2_systems(args)
282 if args.archs or args.arch is not None:
283 dump_v2_archs(args)