Skip to content

Commit

Permalink
[ESI][Runtime] Generate C++ header files for constants (#7517)
Browse files Browse the repository at this point in the history
Start of static C++ header file generation. Just integer constants for now. Can work off of any manifest and will even connect to a live accelerator and read the manifest from there.

Generates a `types.h` file and one per module listed in the manifest. Inside the module header file, generates one class per module and adds the constants to that class. Puts _everything_ in a namespace specified by the user as `system_name`.
  • Loading branch information
teqdruid authored Aug 20, 2024
1 parent 898eb8b commit 29b1c1c
Show file tree
Hide file tree
Showing 12 changed files with 290 additions and 22 deletions.
10 changes: 7 additions & 3 deletions integration_test/Dialect/ESI/runtime/callback.mlir
Original file line number Diff line number Diff line change
@@ -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) -> ()
Expand Down
41 changes: 35 additions & 6 deletions integration_test/Dialect/ESI/runtime/loopback.mlir
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
// 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/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/loopback/
// 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<i8> from "send"]>
!recvI8 = !esi.bundle<[!esi.channel<i8> to "recv"]>
Expand Down Expand Up @@ -109,6 +125,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
Expand Down Expand Up @@ -157,3 +175,14 @@ hw.module @top(in %clk: !seq.clock, in %rst: i1) {
// QUERY-HIER: recv: !esi.channel<i0>
// QUERY-HIER: mysvc_send:
// QUERY-HIER: send: !esi.channel<i0>


// 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
5 changes: 5 additions & 0 deletions integration_test/Dialect/ESI/runtime/loopback.mlir.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "loopback/LoopbackIP.h"

#include <stdio.h>

int main() { printf("depth: 0x%x\n", esi_system::LoopbackIP::depth); }
3 changes: 2 additions & 1 deletion integration_test/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 != "":
Expand Down
1 change: 1 addition & 0 deletions lib/Dialect/ESI/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ set(ESICppRuntimeBackendHeaders
set(ESIPythonRuntimeSources
python/esiaccel/__init__.py
python/esiaccel/accelerator.py
python/esiaccel/codegen.py
python/esiaccel/types.py
python/esiaccel/utils.py
)
Expand Down
3 changes: 3 additions & 0 deletions lib/Dialect/ESI/runtime/cpp/include/esi/backends/Trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
35 changes: 24 additions & 11 deletions lib/Dialect/ESI/runtime/cpp/lib/backends/Trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down Expand Up @@ -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;
Expand All @@ -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);

Expand All @@ -105,7 +111,7 @@ TraceAccelerator::connect(Context &ctxt, std::string connectionString) {

// Parse the connection std::string.
// <mode>:<manifest path>[:<traceFile>]
std::regex connPattern("(\\w):([^:]+)(:(\\w+))?");
std::regex connPattern("([\\w-]):([^:]+)(:(\\w+))?");
std::smatch match;
if (regex_search(connectionString, match, connPattern)) {
modeStr = match[1];
Expand All @@ -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 + "'");

Expand Down Expand Up @@ -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; }
Expand All @@ -276,22 +285,26 @@ class TraceHostMem : public HostMem {
allocate(std::size_t size, HostMem::Options opts) const override {
auto ret =
std::unique_ptr<HostMemRegion>(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:
Expand Down
1 change: 1 addition & 0 deletions lib/Dialect/ESI/runtime/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ classifiers = [
[project.scripts]
esiquery = "esiaccel.utils:run_esiquery"
esi-cosim = "esiaccel.utils:run_esi_cosim"
esi-cppgen = "esiaccel.utils:run_cppgen"
Loading

0 comments on commit 29b1c1c

Please sign in to comment.