Skip to content

Commit

Permalink
[NFC][ESI] Refactor runtime headers and design hierarchy (#6503)
Browse files Browse the repository at this point in the history
- Rename Accelerator to what it really is: an AcceleratorConnection.
- Rename "Design" to "HWModule". Closer, but a slight overloading of
terms.
- Add "Accelerator" as the root of a design hierarchy. It owns or shares
ownership of everything "immortal".
  • Loading branch information
teqdruid authored Dec 8, 2023
1 parent e658bba commit 7910a1e
Show file tree
Hide file tree
Showing 23 changed files with 461 additions and 402 deletions.
3 changes: 1 addition & 2 deletions integration_test/Dialect/ESI/runtime/basic_mmio.sv.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import esi
import os
import sys

acc = esi.Accelerator(sys.argv[1], sys.argv[2])
acc = esi.AcceleratorConnection(sys.argv[1], sys.argv[2])

mmio = acc.get_service_mmio()

Expand Down
4 changes: 2 additions & 2 deletions integration_test/Dialect/ESI/runtime/loopback.mlir.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sys

platform = sys.argv[1]
acc = esi.Accelerator(platform, sys.argv[2])
acc = esi.AcceleratorConnection(platform, sys.argv[2])

assert acc.sysinfo().esi_version() == 1
m = acc.manifest()
Expand Down Expand Up @@ -36,7 +36,7 @@ def strType(t: esi.Type) -> str:
print(f"{esiType}:")
print(f" {strType(esiType)}")

d = m.build_design(acc)
d = m.build_accelerator(acc)

loopback = d.children[esi.AppID("loopback_inst", 0)]
appid = loopback.id
Expand Down
19 changes: 10 additions & 9 deletions lib/Dialect/ESI/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,20 @@ set(ESI_RUNTIME_SRCS

runtime/cpp/include/esi/backends/Cosim.h
runtime/cpp/include/esi/backends/Trace.h
runtime/cpp/include/esi/Utils.h
runtime/cpp/include/esi/Accelerator.h
runtime/cpp/include/esi/Design.h
runtime/cpp/include/esi/Manifest.h
runtime/cpp/include/esi/StdServices.h
runtime/cpp/include/esi/Types.h
runtime/cpp/include/esi/Utils.h
runtime/cpp/include/esi/Ports.h
runtime/cpp/include/esi/Services.h
runtime/cpp/include/esi/Common.h
runtime/cpp/lib/backends/Cosim.cpp
runtime/cpp/lib/backends/Trace.cpp
runtime/cpp/lib/Accelerator.cpp
runtime/cpp/lib/Design.cpp
runtime/cpp/lib/Manifest.cpp
runtime/cpp/lib/StdServices.cpp
runtime/cpp/lib/Utils.cpp
runtime/cpp/lib/Manifest.cpp
runtime/cpp/lib/Services.cpp
runtime/cpp/lib/Accelerator.cpp
runtime/cpp/lib/Ports.cpp
runtime/cpp/tools/esiquery.cpp
runtime/cosim/CMakeLists.txt
runtime/cosim/Cosim_MMIO.sv
Expand All @@ -100,10 +101,10 @@ set(ESI_RUNTIME_SRCS
runtime/cosim/include/cosim/Server.h
runtime/cosim/include/cosim/dpi.h
runtime/cosim/include/dpi/svdpi.h
runtime/cosim/Cosim_Endpoint.sv
runtime/cosim/CosimDpi.capnp
runtime/cosim/Cosim_DpiPkg.sv
runtime/cosim/Cosim_Manifest.sv
runtime/cosim/Cosim_Endpoint.sv
runtime/cosim/CosimDpi.capnp
runtime/python/esi/__init__.py
runtime/python/esi/accelerator.py
runtime/python/esi/esiCppAccel.cpp
Expand Down
4 changes: 2 additions & 2 deletions lib/Dialect/ESI/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ include_directories(cpp/include)

set(ESIRuntimeSources
cpp/lib/Accelerator.cpp
cpp/lib/Design.cpp
cpp/lib/Manifest.cpp
cpp/lib/StdServices.cpp
cpp/lib/Services.cpp
cpp/lib/Ports.cpp
cpp/lib/Utils.cpp

cpp/lib/backends/Trace.cpp
Expand Down
135 changes: 67 additions & 68 deletions lib/Dialect/ESI/runtime/cpp/include/esi/Accelerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
#ifndef ESI_ACCELERATOR_H
#define ESI_ACCELERATOR_H

#include "esi/Design.h"
#include "esi/Manifest.h"
#include "esi/Ports.h"
#include "esi/Services.h"

#include <any>
#include <cstdint>
Expand All @@ -34,92 +35,89 @@

namespace esi {

//===----------------------------------------------------------------------===//
// Constants used by low-level APIs.
//===----------------------------------------------------------------------===//

constexpr uint32_t MagicNumOffset = 16;
constexpr uint32_t MagicNumberLo = 0xE5100E51;
constexpr uint32_t MagicNumberHi = 0x207D98E5;
constexpr uint32_t VersionNumberOffset = MagicNumOffset + 8;
constexpr uint32_t ExpectedVersionNumber = 0;

/// Unidirectional channels are the basic communication primitive between the
/// host and accelerator. A 'ChannelPort' is the host side of a channel. It can
/// be either read or write but not both. At this level, channels are untyped --
/// just streams of bytes. They are not intended to be used directly by users
/// but used by higher level APIs which add types.
class ChannelPort {
public:
ChannelPort(const Type &type) : type(type) {}
virtual ~ChannelPort() = default;

virtual void connect() {}
virtual void disconnect() {}

const Type &getType() const { return type; }
//===----------------------------------------------------------------------===//
// Accelerator design hierarchy.
//===----------------------------------------------------------------------===//

private:
const Type &type;
};
class Instance;

/// A ChannelPort which sends data to the accelerator.
class WriteChannelPort : public ChannelPort {
class HWModule {
public:
using ChannelPort::ChannelPort;
HWModule(std::optional<ModuleInfo> info,
std::vector<std::unique_ptr<Instance>> children,
std::vector<services::Service *> services,
std::vector<BundlePort> ports);

std::optional<ModuleInfo> getInfo() const { return info; }
const std::vector<std::unique_ptr<Instance>> &getChildrenOrdered() const {
return children;
}
const std::map<AppID, Instance *> &getChildren() const { return childIndex; }
const std::vector<BundlePort> &getPortsOrdered() const { return ports; }
const std::map<AppID, const BundlePort &> &getPorts() const {
return portIndex;
}

/// A very basic write API. Will likely change for performance reasons.
virtual void write(const void *data, size_t size) = 0;
protected:
const std::optional<ModuleInfo> info;
const std::vector<std::unique_ptr<Instance>> children;
const std::map<AppID, Instance *> childIndex;
const std::vector<services::Service *> services;
const std::vector<BundlePort> ports;
const std::map<AppID, const BundlePort &> portIndex;
};

/// A ChannelPort which reads data from the accelerator.
class ReadChannelPort : public ChannelPort {
class Instance : public HWModule {
public:
using ChannelPort::ChannelPort;
Instance() = delete;
Instance(const Instance &) = delete;
~Instance() = default;
Instance(AppID id, std::optional<ModuleInfo> info,
std::vector<std::unique_ptr<Instance>> children,
std::vector<services::Service *> services,
std::vector<BundlePort> ports)
: HWModule(info, std::move(children), services, ports), id(id) {}

/// Specify a buffer to read into and a maximum size to read. Returns the
/// number of bytes read, or -1 on error. Basic API, will likely change for
/// performance reasons.
virtual std::ptrdiff_t read(void *data, size_t maxSize) = 0;
};

namespace services {
/// Parent class of all APIs modeled as 'services'. May or may not map to a
/// hardware side 'service'.
class Service {
public:
using Type = const std::type_info &;
virtual ~Service() = default;
const AppID getID() const { return id; }

virtual std::string getServiceSymbol() const = 0;
protected:
const AppID id;
};

/// A service for which there are no standard services registered. Requires
/// ports be added to the design hierarchy instead of high level interfaces like
/// the ones in StdServices.h.
class CustomService : public Service {
class Accelerator : public HWModule {
public:
CustomService(AppIDPath idPath, const ServiceImplDetails &details,
const HWClientDetails &clients);
virtual ~CustomService() = default;

virtual std::string getServiceSymbol() const override {
return serviceSymbol;
}
Accelerator() = delete;
Accelerator(const Accelerator &) = delete;
~Accelerator() = default;
Accelerator(std::optional<ModuleInfo> info,
std::vector<std::unique_ptr<Instance>> children,
std::vector<services::Service *> services,
std::vector<BundlePort> ports,
std::shared_ptr<Manifest::Impl> manifestImpl)
: HWModule(info, std::move(children), services, ports),
manifestImpl(manifestImpl) {}

/// Request the host side channel ports for a particular instance (identified
/// by the AppID path). For convenience, provide the bundle type and direction
/// of the bundle port.
virtual std::map<std::string, ChannelPort &>
requestChannelsFor(AppIDPath, const BundleType &,
BundlePort::Direction portDir) = 0;

protected:
std::string serviceSymbol;
AppIDPath id;
private:
std::shared_ptr<Manifest::Impl> manifestImpl;
};
} // namespace services

/// An ESI accelerator system.
class Accelerator {
//===----------------------------------------------------------------------===//
// Connection to the accelerator and its services.
//===----------------------------------------------------------------------===//

class AcceleratorConnection {
public:
virtual ~Accelerator() = default;
virtual ~AcceleratorConnection() = default;

using Service = services::Service;
/// Get a typed reference to a particular service type. Caller does *not* take
Expand Down Expand Up @@ -159,13 +157,14 @@ namespace registry {

// Connect to an ESI accelerator given a backend name and connection specifier.
// Alternatively, instantiate the backend directly (if you're using C++).
std::unique_ptr<Accelerator> connect(std::string backend,
std::string connection);
std::unique_ptr<AcceleratorConnection> connect(std::string backend,
std::string connection);

namespace internal {

/// Backends can register themselves to be connected via a connection string.
using BackendCreate = std::function<std::unique_ptr<Accelerator>(std::string)>;
using BackendCreate =
std::function<std::unique_ptr<AcceleratorConnection>(std::string)>;
void registerBackend(std::string name, BackendCreate create);

// Helper struct to
Expand Down
88 changes: 88 additions & 0 deletions lib/Dialect/ESI/runtime/cpp/include/esi/Common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//===- Common.h - Commonly used classes w/o dependencies --------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// DO NOT EDIT!
// This file is distributed as part of an ESI package. The source for this file
// should always be modified within CIRCT.
//
//===----------------------------------------------------------------------===//

// NOLINTNEXTLINE(llvm-header-guard)
#ifndef ESI_COMMON_H
#define ESI_COMMON_H

#include <any>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>

namespace esi {

//===----------------------------------------------------------------------===//
// Common accelerator description types.
//===----------------------------------------------------------------------===//

struct AppID {
std::string name;
std::optional<uint32_t> idx;

AppID(const AppID &) = default;
AppID(const std::string &name, std::optional<uint32_t> idx = std::nullopt)
: name(name), idx(idx) {}

bool operator==(const AppID &other) const {
return name == other.name && idx == other.idx;
}
bool operator!=(const AppID &other) const { return !(*this == other); }
};
bool operator<(const AppID &a, const AppID &b);

class AppIDPath : public std::vector<AppID> {
public:
using std::vector<AppID>::vector;

AppIDPath operator+(const AppIDPath &b);
std::string toStr() const;
};
bool operator<(const AppIDPath &a, const AppIDPath &b);
std::ostream &operator<<(std::ostream &, const esi::AppIDPath &);

struct ModuleInfo {
const std::optional<std::string> name;
const std::optional<std::string> summary;
const std::optional<std::string> version;
const std::optional<std::string> repo;
const std::optional<std::string> commitHash;
const std::map<std::string, std::any> extra;
};

/// A description of a service port. Used pretty exclusively in setting up the
/// design.
struct ServicePortDesc {
std::string name;
std::string portName;
};

/// A description of a hardware client. Used pretty exclusively in setting up
/// the design.
struct HWClientDetail {
AppIDPath relPath;
ServicePortDesc port;
std::map<std::string, std::any> implOptions;
};
using HWClientDetails = std::vector<HWClientDetail>;
using ServiceImplDetails = std::map<std::string, std::any>;

} // namespace esi

std::ostream &operator<<(std::ostream &, const esi::ModuleInfo &);
std::ostream &operator<<(std::ostream &, const esi::AppID &);

#endif // ESI_COMMON_H
Loading

0 comments on commit 7910a1e

Please sign in to comment.