From f5a7f62ee90d7feab16956430e4cbc9bc9a8a4f1 Mon Sep 17 00:00:00 2001 From: John Demme Date: Wed, 14 Aug 2024 14:11:55 +0000 Subject: [PATCH 1/3] [ESI][Runtime] Generate C++ header files for constants --- .../Dialect/ESI/runtime/callback.mlir | 10 +- .../Dialect/ESI/runtime/loopback.mlir | 29 ++- .../Dialect/ESI/runtime/loopback.mlir.cpp | 5 + integration_test/lit.cfg.py | 3 +- lib/Dialect/ESI/runtime/CMakeLists.txt | 1 + .../runtime/cpp/include/esi/backends/Trace.h | 3 + .../ESI/runtime/cpp/lib/backends/Trace.cpp | 35 +++- lib/Dialect/ESI/runtime/pyproject.toml | 1 + .../ESI/runtime/python/esiaccel/cppgen.py | 193 ++++++++++++++++++ 9 files changed, 259 insertions(+), 21 deletions(-) create mode 100644 integration_test/Dialect/ESI/runtime/loopback.mlir.cpp create mode 100644 lib/Dialect/ESI/runtime/python/esiaccel/cppgen.py diff --git a/integration_test/Dialect/ESI/runtime/callback.mlir b/integration_test/Dialect/ESI/runtime/callback.mlir index e383d88b9af5..35dd8418bdb3 100644 --- a/integration_test/Dialect/ESI/runtime/callback.mlir +++ b/integration_test/Dialect/ESI/runtime/callback.mlir @@ -1,9 +1,13 @@ // REQUIRES: esi-cosim, esi-runtime, rtl-sim + +// Generate SV files // RUN: rm -rf %t6 && mkdir %t6 && cd %t6 -// RUN: circt-opt %s --esi-connect-services --esi-appid-hier=top=top --esi-build-manifest=top=top --esi-clean-metadata > %t4.mlir -// RUN: circt-opt %t4.mlir --lower-esi-to-physical --lower-esi-bundles --lower-esi-ports --lower-esi-to-hw=platform=cosim --lower-seq-to-sv --lower-hwarith-to-hw --canonicalize --export-split-verilog -o %t3.mlir +// RUN: mkdir hw && cd hw +// RUN: circt-opt %s --esi-connect-services --esi-appid-hier=top=top --esi-build-manifest=top=top --esi-clean-metadata --lower-esi-to-physical --lower-esi-bundles --lower-esi-ports --lower-esi-to-hw=platform=cosim --lower-seq-to-sv --lower-hwarith-to-hw --canonicalize --export-split-verilog // RUN: cd .. -// RUN: esi-cosim.py --source %t6 --top top -- esitester cosim env wait | FileCheck %s + +// Test cosimulation +// RUN: esi-cosim.py --source %t6/hw --top top -- esitester cosim env wait | FileCheck %s hw.module @top(in %clk : !seq.clock, in %rst : i1) { hw.instance "PrintfExample" sym @PrintfExample @PrintfExample(clk: %clk: !seq.clock, rst: %rst: i1) -> () diff --git a/integration_test/Dialect/ESI/runtime/loopback.mlir b/integration_test/Dialect/ESI/runtime/loopback.mlir index 58d039724549..6fc58f74e894 100644 --- a/integration_test/Dialect/ESI/runtime/loopback.mlir +++ b/integration_test/Dialect/ESI/runtime/loopback.mlir @@ -1,12 +1,27 @@ // REQUIRES: esi-cosim, esi-runtime, rtl-sim // RUN: rm -rf %t6 && mkdir %t6 && cd %t6 -// RUN: circt-opt %s --esi-connect-services --esi-appid-hier=top=top --esi-build-manifest=top=top --esi-clean-metadata > %t4.mlir -// RUN: circt-opt %t4.mlir --lower-esi-to-physical --lower-esi-bundles --lower-esi-ports --lower-esi-to-hw=platform=cosim --lower-seq-to-sv --lower-hwarith-to-hw --canonicalize --export-split-verilog -o %t3.mlir + +// Generate SV files +// RUN: mkdir hw && cd hw +// RUN: circt-opt %s --esi-connect-services --esi-appid-hier=top=top --esi-build-manifest=top=top --esi-clean-metadata --lower-esi-to-physical --lower-esi-bundles --lower-esi-ports --lower-esi-to-hw=platform=cosim --lower-seq-to-sv --lower-hwarith-to-hw --canonicalize --export-split-verilog -o %t3.mlir // RUN: cd .. -// RUN: esiquery trace w:%t6/esi_system_manifest.json info | FileCheck %s --check-prefix=QUERY-INFO -// RUN: esiquery trace w:%t6/esi_system_manifest.json hier | FileCheck %s --check-prefix=QUERY-HIER -// RUN: %python %s.py trace w:%t6/esi_system_manifest.json -// RUN: esi-cosim.py --source %t6 --top top -- %python %s.py cosim env + +// Test ESI utils +// RUN: esiquery trace w:%t6/hw/esi_system_manifest.json info | FileCheck %s --check-prefix=QUERY-INFO +// RUN: esiquery trace w:%t6/hw/esi_system_manifest.json hier | FileCheck %s --check-prefix=QUERY-HIER + +// Test cosimulation +// RUN: esi-cosim.py --source %t6/hw --top top -- %python %s.py cosim env + +// Test C++ header generation against the manifest file +// RUN: %python -m esiaccel.cppgen --file %t6/hw/esi_system_manifest.json --output-dir %t6/include +// RUN: %host_cxx -I %t6/include %s.cpp -o %t6/test +// RUN: %t6/test | FileCheck %s --check-prefix=CPP-TEST + +// Test C++ header generation against a live accelerator +// RUN: esi-cosim.py --source %t6 --top top -- %python -m esiaccel.cppgen --platform cosim --connection env --output-dir %t6/include +// RUN: %host_cxx -I %t6/include %s.cpp -o %t6/test +// RUN: %t6/test | FileCheck %s --check-prefix=CPP-TEST !sendI8 = !esi.bundle<[!esi.channel from "send"]> !recvI8 = !esi.bundle<[!esi.channel to "recv"]> @@ -109,6 +124,8 @@ hw.module @top(in %clk: !seq.clock, in %rst: i1) { hw.instance "loopback_array" @LoopbackArray() -> () } +// CPP-TEST: depth: 0x5 + // QUERY-INFO: API version: 0 // QUERY-INFO: ******************************** // QUERY-INFO: * Module information diff --git a/integration_test/Dialect/ESI/runtime/loopback.mlir.cpp b/integration_test/Dialect/ESI/runtime/loopback.mlir.cpp new file mode 100644 index 000000000000..121eedcca1ba --- /dev/null +++ b/integration_test/Dialect/ESI/runtime/loopback.mlir.cpp @@ -0,0 +1,5 @@ +#include "LoopbackIP.h" + +#include + +int main() { printf("depth: 0x%x\n", esi_system::LoopbackIP::depth); } diff --git a/integration_test/lit.cfg.py b/integration_test/lit.cfg.py index 6788cfa8a9f8..f3de280b120e 100644 --- a/integration_test/lit.cfg.py +++ b/integration_test/lit.cfg.py @@ -187,8 +187,9 @@ if config.bindings_tcl_enabled: config.available_features.add('bindings_tcl') -# Add host c compiler. +# Add host c/c++ compiler. config.substitutions.append(("%host_cc", config.host_cc)) +config.substitutions.append(("%host_cxx", config.host_cxx)) # Enable clang-tidy if it has been detected. if config.clang_tidy_path != "": diff --git a/lib/Dialect/ESI/runtime/CMakeLists.txt b/lib/Dialect/ESI/runtime/CMakeLists.txt index fdda1847c2da..146593c28610 100644 --- a/lib/Dialect/ESI/runtime/CMakeLists.txt +++ b/lib/Dialect/ESI/runtime/CMakeLists.txt @@ -122,6 +122,7 @@ set(ESICppRuntimeBackendHeaders set(ESIPythonRuntimeSources python/esiaccel/__init__.py python/esiaccel/accelerator.py + python/esiaccel/cppgen.py python/esiaccel/types.py python/esiaccel/utils.py ) diff --git a/lib/Dialect/ESI/runtime/cpp/include/esi/backends/Trace.h b/lib/Dialect/ESI/runtime/cpp/include/esi/backends/Trace.h index ff5416bb4398..5cd0406e0050 100644 --- a/lib/Dialect/ESI/runtime/cpp/include/esi/backends/Trace.h +++ b/lib/Dialect/ESI/runtime/cpp/include/esi/backends/Trace.h @@ -43,6 +43,9 @@ class TraceAccelerator : public esi::AcceleratorConnection { // Data read from the accelerator is read from the trace file. // TODO: Full trace mode not yet supported. // Read + + // Discard all data sent to the accelerator. Disable trace file generation. + Discard, }; /// Create a trace-based accelerator backend. diff --git a/lib/Dialect/ESI/runtime/cpp/lib/backends/Trace.cpp b/lib/Dialect/ESI/runtime/cpp/lib/backends/Trace.cpp index a69f657b75df..f6e89826fee8 100644 --- a/lib/Dialect/ESI/runtime/cpp/lib/backends/Trace.cpp +++ b/lib/Dialect/ESI/runtime/cpp/lib/backends/Trace.cpp @@ -49,6 +49,8 @@ struct esi::backends::trace::TraceAccelerator::Impl { if (!traceWrite->is_open()) throw std::runtime_error("failed to open trace file '" + traceFile.string() + "'"); + } else if (mode == Discard) { + traceWrite = nullptr; } else { assert(false && "not implemented"); } @@ -76,9 +78,11 @@ struct esi::backends::trace::TraceAccelerator::Impl { void write(const AppIDPath &id, const std::string &portName, const void *data, size_t size); std::ostream &write(std::string service) { + assert(traceWrite && "traceWrite is null"); *traceWrite << "[" << service << "] "; return *traceWrite; } + bool isWriteable() { return traceWrite; } private: std::ofstream *traceWrite; @@ -90,6 +94,8 @@ struct esi::backends::trace::TraceAccelerator::Impl { void TraceAccelerator::Impl::write(const AppIDPath &id, const std::string &portName, const void *data, size_t size) { + if (!isWriteable()) + return; std::string b64data; utils::encodeBase64(data, size, b64data); @@ -105,7 +111,7 @@ TraceAccelerator::connect(Context &ctxt, std::string connectionString) { // Parse the connection std::string. // :[:] - std::regex connPattern("(\\w):([^:]+)(:(\\w+))?"); + std::regex connPattern("([\\w-]):([^:]+)(:(\\w+))?"); std::smatch match; if (regex_search(connectionString, match, connPattern)) { modeStr = match[1]; @@ -121,6 +127,8 @@ TraceAccelerator::connect(Context &ctxt, std::string connectionString) { Mode mode; if (modeStr == "w") mode = Write; + else if (modeStr == "-") + mode = Discard; else throw std::runtime_error("unknown mode '" + modeStr + "'"); @@ -260,7 +268,8 @@ class TraceHostMem : public HostMem { this->size = size; } virtual ~TraceHostMemRegion() { - impl.write("HostMem") << "free " << ptr << std::endl; + if (impl.isWriteable()) + impl.write("HostMem") << "free " << ptr << std::endl; free(ptr); } virtual void *getPtr() const override { return ptr; } @@ -276,22 +285,26 @@ class TraceHostMem : public HostMem { allocate(std::size_t size, HostMem::Options opts) const override { auto ret = std::unique_ptr(new TraceHostMemRegion(size, impl)); - impl.write("HostMem 0x") - << ret->getPtr() << " allocate " << size - << " bytes. Writeable: " << opts.writeable - << ", useLargePages: " << opts.useLargePages << std::endl; + if (impl.isWriteable()) + impl.write("HostMem 0x") + << ret->getPtr() << " allocate " << size + << " bytes. Writeable: " << opts.writeable + << ", useLargePages: " << opts.useLargePages << std::endl; return ret; } virtual bool mapMemory(void *ptr, std::size_t size, HostMem::Options opts) const override { - impl.write("HostMem") << "map 0x" << ptr << " size " << size - << " bytes. Writeable: " << opts.writeable - << ", useLargePages: " << opts.useLargePages - << std::endl; + + if (impl.isWriteable()) + impl.write("HostMem") + << "map 0x" << ptr << " size " << size + << " bytes. Writeable: " << opts.writeable + << ", useLargePages: " << opts.useLargePages << std::endl; return true; } virtual void unmapMemory(void *ptr) const override { - impl.write("HostMem") << "unmap 0x" << ptr << std::endl; + if (impl.isWriteable()) + impl.write("HostMem") << "unmap 0x" << ptr << std::endl; } private: diff --git a/lib/Dialect/ESI/runtime/pyproject.toml b/lib/Dialect/ESI/runtime/pyproject.toml index 4099d43a6d60..344d05864dac 100644 --- a/lib/Dialect/ESI/runtime/pyproject.toml +++ b/lib/Dialect/ESI/runtime/pyproject.toml @@ -44,3 +44,4 @@ classifiers = [ [project.scripts] esiquery = "esiaccel.utils:run_esiquery" esi-cosim = "esiaccel.utils:run_esi_cosim" +esi-cppgen = "esiaccel.cppgen:run" diff --git a/lib/Dialect/ESI/runtime/python/esiaccel/cppgen.py b/lib/Dialect/ESI/runtime/python/esiaccel/cppgen.py new file mode 100644 index 000000000000..070fffb292e5 --- /dev/null +++ b/lib/Dialect/ESI/runtime/python/esiaccel/cppgen.py @@ -0,0 +1,193 @@ +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# Code generation from ESI manifests to C++ headers. Intended to be extensible +# for other languages. + +from typing import List, Type, Optional +from .accelerator import AcceleratorConnection +from .esiCppAccel import ModuleInfo +from . import types + +import argparse +from pathlib import Path +import textwrap +import sys + +_thisdir = Path(__file__).absolute().resolve().parent + + +class Generator: + """Base class for all generators.""" + + language: Optional[str] = None + + def __init__(self, conn: AcceleratorConnection): + self.manifest = conn.manifest() + + def generate(self, output_dir: Path, system_name: str): + raise NotImplementedError("Generator.generate() must be overridden") + + +class CppGenerator(Generator): + """Generate C++ headers from an ESI manifest.""" + + language = "C++" + + # Supported bit widths for lone integer types. + int_width_support = set([8, 16, 32, 64]) + + def get_type_str(self, type: types.ESIType) -> str: + """Get the textual code for the storage class of a type. + + Examples: uint32_t, int64_t, CustomStruct.""" + + if isinstance(type, (types.BitsType, types.IntType)): + if type.bit_width not in self.int_width_support: + raise ValueError(f"Unsupported integer width: {type.bit_width}") + if isinstance(type, (types.BitsType, types.UIntType)): + return f"uint{type.bit_width}_t" + return f"int{type.bit_width}_t" + raise NotImplementedError(f"Type '{type}' not supported for C++ generation") + + def get_consts_str(self, module_info: ModuleInfo) -> str: + """Get the C++ code for a constant in a module.""" + const_strs: List[str] = [ + f"static constexpr {self.get_type_str(const.type)} " + f"{name} = 0x{const.value:x};" + for name, const in module_info.constants.items() + ] + return "\n".join(const_strs) + + def write_modules(self, output_dir: Path, system_name: str): + """Write the C++ one header for each module in the manifest.""" + + for module_info in self.manifest.module_infos: + s = f""" + /// Generated header for {system_name} module {module_info.name}. + #pragma once + #include "types.h" + + namespace {system_name} {{ + class {module_info.name} {{ + public: + {self.get_consts_str(module_info)} + }}; + }} // namespace {system_name} + """ + + hdr_file = output_dir / f"{module_info.name}.h" + with open(hdr_file, "w") as hdr: + hdr.write(textwrap.dedent(s)) + + def write_type(self, hdr, type: types.ESIType): + if isinstance(type, (types.BitsType, types.IntType)): + # Bit vector types use standard C++ types. + return + raise NotImplementedError(f"Type '{type}' not supported for C++ generation") + + def write_types(self, output_dir: Path, system_name: str): + hdr_file = output_dir / "types.h" + with open(hdr_file, "w") as hdr: + hdr.write( + textwrap.dedent(f""" + // Generated header for {system_name} types. + #pragma once + + #include + + namespace {system_name} {{ + """)) + + for type in self.manifest.type_table: + try: + self.write_type(hdr, type) + except NotImplementedError: + sys.stderr.write( + f"Warning: type '{type}' not supported for C++ generation\n") + + hdr.write( + textwrap.dedent(f""" + }} // namespace {system_name} + """)) + + def generate(self, output_dir: Path, system_name: str): + self.write_types(output_dir, system_name) + self.write_modules(output_dir, system_name) + + +def run(generator: Type[Generator] = CppGenerator, + cmdline_args=sys.argv) -> int: + """Create and run a generator reading options from the command line.""" + + argparser = argparse.ArgumentParser( + description=f"Generate {generator.language} headers from an ESI manifest", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=textwrap.dedent(""" + Can read the manifest from either a file OR a running accelerator. + + Usage examples: + # To read the manifest from a file: + esi-cppgen --file /path/to/manifest.json + + # To read the manifest from a running accelerator: + esi-cppgen --platform cosim --connection localhost:1234 + """)) + + argparser.add_argument("--file", + type=str, + default=None, + help="Path to the manifest file.") + argparser.add_argument( + "--platform", + type=str, + help="Name of backend for live accelerator connection.") + argparser.add_argument( + "--connection", + type=str, + help="Connection string for live accelerator connection.") + argparser.add_argument("--output-dir", + type=str, + default=".", + help="Output directory for generated files.") + argparser.add_argument("--system-name", + type=str, + default="esi_system", + help="Name of the ESI system.") + + if (len(cmdline_args) <= 1): + argparser.print_help() + return 1 + args = argparser.parse_args(cmdline_args[1:]) + + if args.file is not None and args.platform is not None: + print("Cannot specify both --file and --platform") + return 1 + + conn: AcceleratorConnection + if args.file is not None: + conn = AcceleratorConnection("trace", f"-:{args.file}") + elif args.platform is not None: + if args.connection is None: + print("Must specify --connection with --platform") + return 1 + conn = AcceleratorConnection(args.platform, args.connection) + else: + print("Must specify either --file or --platform") + return 1 + + output_dir = Path(args.output_dir) + if output_dir.exists() and not output_dir.is_dir(): + print(f"Output directory {output_dir} is not a directory") + return 1 + if not output_dir.exists(): + output_dir.mkdir(parents=True) + + gen = generator(conn) + gen.generate(output_dir, args.system_name) + return 0 + + +if __name__ == '__main__': + sys.exit(run()) From dfe22fd0db7dd73204609e6788754896153cd7ce Mon Sep 17 00:00:00 2001 From: John Demme Date: Mon, 19 Aug 2024 15:01:15 +0000 Subject: [PATCH 2/3] Some Morten's feedback, some bugfix --- .../Dialect/ESI/runtime/loopback.mlir | 16 ++++++++-- .../Dialect/ESI/runtime/loopback.mlir.cpp | 2 +- lib/Dialect/ESI/runtime/CMakeLists.txt | 2 +- lib/Dialect/ESI/runtime/pyproject.toml | 2 +- .../python/esiaccel/{cppgen.py => codegen.py} | 32 +++++++++++-------- .../runtime/python/esiaccel/esiCppAccel.cpp | 9 +++++- .../ESI/runtime/python/esiaccel/types.py | 1 + .../ESI/runtime/python/esiaccel/utils.py | 6 ++++ 8 files changed, 50 insertions(+), 20 deletions(-) rename lib/Dialect/ESI/runtime/python/esiaccel/{cppgen.py => codegen.py} (86%) diff --git a/integration_test/Dialect/ESI/runtime/loopback.mlir b/integration_test/Dialect/ESI/runtime/loopback.mlir index 6fc58f74e894..b38c8d71e5bb 100644 --- a/integration_test/Dialect/ESI/runtime/loopback.mlir +++ b/integration_test/Dialect/ESI/runtime/loopback.mlir @@ -14,12 +14,13 @@ // RUN: esi-cosim.py --source %t6/hw --top top -- %python %s.py cosim env // Test C++ header generation against the manifest file -// RUN: %python -m esiaccel.cppgen --file %t6/hw/esi_system_manifest.json --output-dir %t6/include +// RUN: %python -m esiaccel.cppgen --file %t6/hw/esi_system_manifest.json --output-dir %t6/include/loopback/ // RUN: %host_cxx -I %t6/include %s.cpp -o %t6/test // RUN: %t6/test | FileCheck %s --check-prefix=CPP-TEST +// RUN: FileCheck %s --check-prefix=LOOPBACK-H --input-file %t6/include/loopback/LoopbackIP.h // Test C++ header generation against a live accelerator -// RUN: esi-cosim.py --source %t6 --top top -- %python -m esiaccel.cppgen --platform cosim --connection env --output-dir %t6/include +// RUN: esi-cosim.py --source %t6 --top top -- %python -m esiaccel.cppgen --platform cosim --connection env --output-dir %t6/include/loopback/ // RUN: %host_cxx -I %t6/include %s.cpp -o %t6/test // RUN: %t6/test | FileCheck %s --check-prefix=CPP-TEST @@ -174,3 +175,14 @@ hw.module @top(in %clk: !seq.clock, in %rst: i1) { // QUERY-HIER: recv: !esi.channel // QUERY-HIER: mysvc_send: // QUERY-HIER: send: !esi.channel + + +// LOOPBACK-H: /// Generated header for esi_system module LoopbackIP. +// LOOPBACK-H-NEXT: #pragma once +// LOOPBACK-H-NEXT: #include "types.h" +// LOOPBACK-H-LABEL: namespace esi_system { +// LOOPBACK-H-LABEL: class LoopbackIP { +// LOOPBACK-H-NEXT: public: +// LOOPBACK-H-NEXT: static constexpr uint32_t depth = 0x5; +// LOOPBACK-H-NEXT: }; +// LOOPBACK-H-NEXT: } // namespace esi_system diff --git a/integration_test/Dialect/ESI/runtime/loopback.mlir.cpp b/integration_test/Dialect/ESI/runtime/loopback.mlir.cpp index 121eedcca1ba..f9950359498a 100644 --- a/integration_test/Dialect/ESI/runtime/loopback.mlir.cpp +++ b/integration_test/Dialect/ESI/runtime/loopback.mlir.cpp @@ -1,4 +1,4 @@ -#include "LoopbackIP.h" +#include "loopback/LoopbackIP.h" #include diff --git a/lib/Dialect/ESI/runtime/CMakeLists.txt b/lib/Dialect/ESI/runtime/CMakeLists.txt index 146593c28610..ac5312ada65b 100644 --- a/lib/Dialect/ESI/runtime/CMakeLists.txt +++ b/lib/Dialect/ESI/runtime/CMakeLists.txt @@ -122,7 +122,7 @@ set(ESICppRuntimeBackendHeaders set(ESIPythonRuntimeSources python/esiaccel/__init__.py python/esiaccel/accelerator.py - python/esiaccel/cppgen.py + python/esiaccel/codegen.py python/esiaccel/types.py python/esiaccel/utils.py ) diff --git a/lib/Dialect/ESI/runtime/pyproject.toml b/lib/Dialect/ESI/runtime/pyproject.toml index 344d05864dac..5ec0f81ae2aa 100644 --- a/lib/Dialect/ESI/runtime/pyproject.toml +++ b/lib/Dialect/ESI/runtime/pyproject.toml @@ -44,4 +44,4 @@ classifiers = [ [project.scripts] esiquery = "esiaccel.utils:run_esiquery" esi-cosim = "esiaccel.utils:run_esi_cosim" -esi-cppgen = "esiaccel.cppgen:run" +esi-cppgen = "esiaccel.utils:run_cppgen" diff --git a/lib/Dialect/ESI/runtime/python/esiaccel/cppgen.py b/lib/Dialect/ESI/runtime/python/esiaccel/codegen.py similarity index 86% rename from lib/Dialect/ESI/runtime/python/esiaccel/cppgen.py rename to lib/Dialect/ESI/runtime/python/esiaccel/codegen.py index 070fffb292e5..b90b780f0818 100644 --- a/lib/Dialect/ESI/runtime/python/esiaccel/cppgen.py +++ b/lib/Dialect/ESI/runtime/python/esiaccel/codegen.py @@ -2,10 +2,10 @@ # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# Code generation from ESI manifests to C++ headers. Intended to be extensible -# for other languages. +# Code generation from ESI manifests to source code. C++ header support included +# with the runtime, though it is intended to be extensible for other languages. -from typing import List, Type, Optional +from typing import List, TextIO, Type, Optional from .accelerator import AcceleratorConnection from .esiCppAccel import ModuleInfo from . import types @@ -61,7 +61,7 @@ def get_consts_str(self, module_info: ModuleInfo) -> str: return "\n".join(const_strs) def write_modules(self, output_dir: Path, system_name: str): - """Write the C++ one header for each module in the manifest.""" + """Write the C++ header. One for each module in the manifest.""" for module_info in self.manifest.module_infos: s = f""" @@ -81,7 +81,7 @@ class {module_info.name} {{ with open(hdr_file, "w") as hdr: hdr.write(textwrap.dedent(s)) - def write_type(self, hdr, type: types.ESIType): + def write_type(self, hdr: TextIO, type: types.ESIType): if isinstance(type, (types.BitsType, types.IntType)): # Bit vector types use standard C++ types. return @@ -142,19 +142,23 @@ def run(generator: Type[Generator] = CppGenerator, argparser.add_argument( "--platform", type=str, - help="Name of backend for live accelerator connection.") + help="Name of platform for live accelerator connection.") argparser.add_argument( "--connection", type=str, help="Connection string for live accelerator connection.") - argparser.add_argument("--output-dir", - type=str, - default=".", - help="Output directory for generated files.") - argparser.add_argument("--system-name", - type=str, - default="esi_system", - help="Name of the ESI system.") + argparser.add_argument( + "--output-dir", + type=str, + default="esi", + help="Output directory for generated files. Recommend adding either `esi`" + " or the system name to the end of the path so as to avoid header name" + "conflicts. Defaults to `esi`") + argparser.add_argument( + "--system-name", + type=str, + default="esi_system", + help="Name of the ESI system. For C++, this will be the namespace.") if (len(cmdline_args) <= 1): argparser.print_help() diff --git a/lib/Dialect/ESI/runtime/python/esiaccel/esiCppAccel.cpp b/lib/Dialect/ESI/runtime/python/esiaccel/esiCppAccel.cpp index 051106ecc5e2..8b7730ae8e87 100644 --- a/lib/Dialect/ESI/runtime/python/esiaccel/esiCppAccel.cpp +++ b/lib/Dialect/ESI/runtime/python/esiaccel/esiCppAccel.cpp @@ -329,6 +329,13 @@ PYBIND11_MODULE(esiCppAccel, m) { return acc; }, py::return_value_policy::reference) - .def_property_readonly("type_table", &Manifest::getTypeTable) + .def_property_readonly("type_table", + [](Manifest &m) { + std::vector ret; + std::ranges::transform(m.getTypeTable(), + std::back_inserter(ret), + getPyType); + return ret; + }) .def_property_readonly("module_infos", &Manifest::getModuleInfos); } diff --git a/lib/Dialect/ESI/runtime/python/esiaccel/types.py b/lib/Dialect/ESI/runtime/python/esiaccel/types.py index eccff627508e..1b1041247522 100644 --- a/lib/Dialect/ESI/runtime/python/esiaccel/types.py +++ b/lib/Dialect/ESI/runtime/python/esiaccel/types.py @@ -47,6 +47,7 @@ def supports_host(self) -> Tuple[bool, Optional[str]]: """Does this type support host communication via Python? Returns either '(True, None)' if it is, or '(False, reason)' if it is not.""" + print(f"supports_host: {self.cpp_type} {type(self)}") if self.bit_width % 8 != 0: return (False, "runtime only supports types with multiple of 8 bits") return (True, None) diff --git a/lib/Dialect/ESI/runtime/python/esiaccel/utils.py b/lib/Dialect/ESI/runtime/python/esiaccel/utils.py index c0e9d831dd85..29d92b1d79cb 100644 --- a/lib/Dialect/ESI/runtime/python/esiaccel/utils.py +++ b/lib/Dialect/ESI/runtime/python/esiaccel/utils.py @@ -2,6 +2,8 @@ # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +from . import codegen + from pathlib import Path import subprocess import sys @@ -26,5 +28,9 @@ def run_esi_cosim(): return cosim_import.__main__(sys.argv) +def run_cppgen(): + return codegen.run() + + def get_cmake_dir(): return _thisdir / "cmake" From 5cf05806e32201c02b9d3a4f799af3c79ace3f46 Mon Sep 17 00:00:00 2001 From: John Demme Date: Mon, 19 Aug 2024 15:05:11 +0000 Subject: [PATCH 3/3] whitespace change --- integration_test/Dialect/ESI/runtime/loopback.mlir | 8 ++++---- lib/Dialect/ESI/runtime/python/esiaccel/codegen.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/integration_test/Dialect/ESI/runtime/loopback.mlir b/integration_test/Dialect/ESI/runtime/loopback.mlir index b38c8d71e5bb..92dd32b7b934 100644 --- a/integration_test/Dialect/ESI/runtime/loopback.mlir +++ b/integration_test/Dialect/ESI/runtime/loopback.mlir @@ -181,8 +181,8 @@ hw.module @top(in %clk: !seq.clock, in %rst: i1) { // LOOPBACK-H-NEXT: #pragma once // LOOPBACK-H-NEXT: #include "types.h" // LOOPBACK-H-LABEL: namespace esi_system { -// LOOPBACK-H-LABEL: class LoopbackIP { -// LOOPBACK-H-NEXT: public: -// LOOPBACK-H-NEXT: static constexpr uint32_t depth = 0x5; -// LOOPBACK-H-NEXT: }; +// LOOPBACK-H-LABEL: class LoopbackIP { +// LOOPBACK-H-NEXT: public: +// LOOPBACK-H-NEXT: static constexpr uint32_t depth = 0x5; +// LOOPBACK-H-NEXT: }; // LOOPBACK-H-NEXT: } // namespace esi_system diff --git a/lib/Dialect/ESI/runtime/python/esiaccel/codegen.py b/lib/Dialect/ESI/runtime/python/esiaccel/codegen.py index b90b780f0818..4fd1eed65c81 100644 --- a/lib/Dialect/ESI/runtime/python/esiaccel/codegen.py +++ b/lib/Dialect/ESI/runtime/python/esiaccel/codegen.py @@ -70,10 +70,10 @@ def write_modules(self, output_dir: Path, system_name: str): #include "types.h" namespace {system_name} {{ - class {module_info.name} {{ - public: - {self.get_consts_str(module_info)} - }}; + class {module_info.name} {{ + public: + {self.get_consts_str(module_info)} + }}; }} // namespace {system_name} """