8 from typing
import List, TextIO, Type, Optional
9 from .accelerator
import AcceleratorConnection
10 from .esiCppAccel
import ModuleInfo
14 from pathlib
import Path
18 _thisdir = Path(__file__).absolute().resolve().parent
22 """Base class for all generators."""
24 language: Optional[str] =
None
26 def __init__(self, conn: AcceleratorConnection):
29 def generate(self, output_dir: Path, system_name: str):
30 raise NotImplementedError(
"Generator.generate() must be overridden")
34 """Generate C++ headers from an ESI manifest."""
39 int_width_support = set([8, 16, 32, 64])
42 """Get the textual code for the storage class of a type.
44 Examples: uint32_t, int64_t, CustomStruct."""
48 raise ValueError(f
"Unsupported integer width: {type.bit_width}")
50 return f
"uint{type.bit_width}_t"
51 return f
"int{type.bit_width}_t"
52 raise NotImplementedError(f
"Type '{type}' not supported for C++ generation")
55 """Get the C++ code for a constant in a module."""
56 const_strs: List[str] = [
57 f
"static constexpr {self.get_type_str(const.type)} "
58 f
"{name} = 0x{const.value:x};"
59 for name, const
in module_info.constants.items()
61 return "\n".join(const_strs)
64 """Write the C++ header. One for each module in the manifest."""
66 for module_info
in self.
manifestmanifest.module_infos:
68 /// Generated header for {system_name} module {module_info.name}.
72 namespace {system_name} {{
73 class {module_info.name} {{
75 {self.get_consts_str(module_info)}
77 }} // namespace {system_name}
80 hdr_file = output_dir / f
"{module_info.name}.h"
81 with open(hdr_file,
"w")
as hdr:
82 hdr.write(textwrap.dedent(s))
88 raise NotImplementedError(f
"Type '{type}' not supported for C++ generation")
91 hdr_file = output_dir /
"types.h"
92 with open(hdr_file,
"w")
as hdr:
95 // Generated header for {system_name} types.
100 namespace {system_name} {{
103 for type
in self.
manifestmanifest.type_table:
106 except NotImplementedError:
108 f
"Warning: type '{type}' not supported for C++ generation\n")
112 }} // namespace {system_name}
115 def generate(self, output_dir: Path, system_name: str):
116 self.
write_typeswrite_types(output_dir, system_name)
120 def run(generator: Type[Generator] = CppGenerator,
121 cmdline_args=sys.argv) -> int:
122 """Create and run a generator reading options from the command line."""
124 argparser = argparse.ArgumentParser(
125 description=f
"Generate {generator.language} headers from an ESI manifest",
126 formatter_class=argparse.RawDescriptionHelpFormatter,
127 epilog=textwrap.dedent(
"""
128 Can read the manifest from either a file OR a running accelerator.
131 # To read the manifest from a file:
132 esi-cppgen --file /path/to/manifest.json
134 # To read the manifest from a running accelerator:
135 esi-cppgen --platform cosim --connection localhost:1234
138 argparser.add_argument(
"--file",
141 help=
"Path to the manifest file.")
142 argparser.add_argument(
145 help=
"Name of platform for live accelerator connection.")
146 argparser.add_argument(
149 help=
"Connection string for live accelerator connection.")
150 argparser.add_argument(
154 help=
"Output directory for generated files. Recommend adding either `esi`"
155 " or the system name to the end of the path so as to avoid header name"
156 "conflicts. Defaults to `esi`")
157 argparser.add_argument(
160 default=
"esi_system",
161 help=
"Name of the ESI system. For C++, this will be the namespace.")
163 if (len(cmdline_args) <= 1):
164 argparser.print_help()
166 args = argparser.parse_args(cmdline_args[1:])
168 if args.file
is not None and args.platform
is not None:
169 print(
"Cannot specify both --file and --platform")
172 conn: AcceleratorConnection
173 if args.file
is not None:
175 elif args.platform
is not None:
176 if args.connection
is None:
177 print(
"Must specify --connection with --platform")
181 print(
"Must specify either --file or --platform")
184 output_dir = Path(args.output_dir)
185 if output_dir.exists()
and not output_dir.is_dir():
186 print(f
"Output directory {output_dir} is not a directory")
188 if not output_dir.exists():
189 output_dir.mkdir(parents=
True)
191 gen = generator(conn)
192 gen.generate(output_dir, args.system_name)
196 if __name__ ==
'__main__':
str get_type_str(self, types.ESIType type)
str get_consts_str(self, ModuleInfo module_info)
def generate(self, Path output_dir, str system_name)
def write_type(self, TextIO hdr, types.ESIType type)
def write_modules(self, Path output_dir, str system_name)
def write_types(self, Path output_dir, str system_name)
def __init__(self, AcceleratorConnection conn)
def generate(self, Path output_dir, str system_name)
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)