diff --git a/CMakeLists.txt b/CMakeLists.txt index 534a9f80b1ac1..debae52b9d365 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ tvm_option(USE_RELAY_DEBUG "Building Relay in debug mode..." OFF) tvm_option(USE_SGX "Build with SGX" OFF) tvm_option(USE_RTTI "Build with RTTI" ON) tvm_option(USE_MSVC_MT "Build with MT" OFF) +tvm_option(USE_MICRO "Build with Micro" OFF) tvm_option(INSTALL_DEV "Install compiler infrastructure" OFF) tvm_option(HIDE_PRIVATE_SYMBOLS "Compile with -fvisibility=hidden." OFF) @@ -207,6 +208,7 @@ include(cmake/modules/Metal.cmake) include(cmake/modules/ROCM.cmake) include(cmake/modules/SGX.cmake) include(cmake/modules/LLVM.cmake) +include(cmake/modules/Micro.cmake) include(cmake/modules/ANTLR.cmake) include(cmake/modules/contrib/BLAS.cmake) include(cmake/modules/contrib/Random.cmake) diff --git a/cmake/config.cmake b/cmake/config.cmake index 6239bc4e6dce3..97173eec04b78 100644 --- a/cmake/config.cmake +++ b/cmake/config.cmake @@ -62,6 +62,9 @@ set(USE_VULKAN OFF) # Whether enable OpenGL runtime set(USE_OPENGL OFF) +# Whether enable Micro runtime +set(USE_MICRO OFF) + # Whether to enable SGX runtime # # Possible values for USE_SGX: diff --git a/cmake/modules/Micro.cmake b/cmake/modules/Micro.cmake new file mode 100644 index 0000000000000..28d292e94143e --- /dev/null +++ b/cmake/modules/Micro.cmake @@ -0,0 +1,5 @@ +if(USE_MICRO) + message(STATUS "Build with Micro support") + file(GLOB RUNTIME_MICRO_SRCS src/runtime/micro/*.cc) + list(APPEND RUNTIME_SRCS ${RUNTIME_MICRO_SRCS}) +endif(USE_MICRO) diff --git a/include/tvm/runtime/c_runtime_api.h b/include/tvm/runtime/c_runtime_api.h index ba2c0d2291b68..0bf032d31ce31 100644 --- a/include/tvm/runtime/c_runtime_api.h +++ b/include/tvm/runtime/c_runtime_api.h @@ -81,6 +81,7 @@ typedef enum { kDLAOCL = 5, kDLSDAccel = 6, kOpenGL = 11, + kDLMicroDev = 13, // AddExtraTVMType which is not in DLPack here } TVMDeviceExtType; diff --git a/python/tvm/_ffi/runtime_ctypes.py b/python/tvm/_ffi/runtime_ctypes.py index 72cff1a10eadb..a418ea7c523ba 100644 --- a/python/tvm/_ffi/runtime_ctypes.py +++ b/python/tvm/_ffi/runtime_ctypes.py @@ -143,6 +143,7 @@ class TVMContext(ctypes.Structure): 10: 'rocm', 11: 'opengl', 12: 'ext_dev', + 13: 'micro_dev', } STR2MASK = { 'llvm': 1, @@ -163,6 +164,7 @@ class TVMContext(ctypes.Structure): 'rocm': 10, 'opengl': 11, 'ext_dev': 12, + 'micro_dev': 13, } def __init__(self, device_type, device_id): super(TVMContext, self).__init__() diff --git a/src/runtime/micro/allocator_stream.h b/src/runtime/micro/allocator_stream.h new file mode 100644 index 0000000000000..4e4ff5193fb91 --- /dev/null +++ b/src/runtime/micro/allocator_stream.h @@ -0,0 +1,108 @@ +/*! + * Copyright (c) 2019 by Contributors + * \file allocator_stream.h + * \brief allocator stream utility + */ +#ifndef TVM_RUNTIME_MICRO_ALLOCATOR_STREAM_H_ +#define TVM_RUNTIME_MICRO_ALLOCATOR_STREAM_H_ + +#include +#include +#include +#include +#include + +namespace tvm { +namespace runtime { +/*! + * \brief allocation-based stream with bounded buffer size for uTVM args allocation + * \note based on dmlc::MemoryStringStream + */ +struct AllocatorStream : public dmlc::SeekStream { + public: + /*! + * \brief constructor + * \param p_buffer the pointer to the string. + */ + explicit AllocatorStream(std::string *p_buffer) + : p_buffer_(p_buffer) { + curr_ptr_ = 0; + max_ptr_ = 0; + } + + /*! + * \brief reads size bytes of data starting at ptr + * \param ptr address to begin read + * \param size number of bytes to be read + * \return number of bytes read + */ + size_t Read(void *ptr, size_t size) { + CHECK(curr_ptr_ <= p_buffer_->length()); + CHECK(curr_ptr_ + size <= max_ptr_); + size_t nread = std::min(p_buffer_->length() - curr_ptr_, size); + if (nread != 0) std::memcpy(ptr, &(*p_buffer_)[0] + curr_ptr_, nread); + curr_ptr_ += nread; + return nread; + } + + /*! + * \brief writes size bytes of data starting at ptr + * \param ptr address of the buffer to be written + * \param size number of bytes to be written + */ + void Write(const void *ptr, size_t size) { + if (size == 0) return; + CHECK(curr_ptr_ + size <= max_ptr_); + if (curr_ptr_ + size > p_buffer_->length()) { + p_buffer_->resize(curr_ptr_+size); + } + std::memcpy(&(*p_buffer_)[0] + curr_ptr_, ptr, size); + curr_ptr_ += size; + } + + /*! + * \brief seek to specified location within internal buffer + * \param pos seek position from start in bytes + */ + void Seek(size_t pos) { + curr_ptr_ = static_cast(pos); + } + + /*! + * \brief get seek pointer location + * \return current seek pointer location from start in bytes + */ + size_t Tell(void) { + return curr_ptr_; + } + + /*! + * \brief allocates an empty region within the stream buffer + * \param size size of the allocated region + * \return offset bytes of the allocated region from start of the buffer + */ + size_t Allocate(size_t size) { + size_t ret = max_ptr_; + max_ptr_ += size; + return ret; + } + + /*! + * \brief returns current size of the stream buffer + * \return buffer size + */ + size_t GetBufferSize() { + return max_ptr_; + } + + private: + /*! \brief in memory buffer */ + std::string *p_buffer_; + /*! \brief current pointer */ + size_t curr_ptr_; + /*! \brief maximum pointer */ + size_t max_ptr_; +}; +} // namespace runtime +} // namespace tvm +#endif // TVM_RUNTIME_MICRO_ALLOCATOR_STREAM_H_ diff --git a/src/runtime/micro/device/utvm_runtime.cc b/src/runtime/micro/device/utvm_runtime.cc new file mode 100644 index 0000000000000..3116390a30330 --- /dev/null +++ b/src/runtime/micro/device/utvm_runtime.cc @@ -0,0 +1,20 @@ +/*! + * Copyright (c) 2019 by Contributors + * \file utvm_runtime.cc + * \brief micro device init stub + */ +#include "utvm_runtime.h" + +// task pointers must be patched before calling a function +UTVMTask task; + +// dummy function to signal execution is finished +void UTVMDone() {} + +// init stub +int UTVMMain() +{ + task.func(task.args, task.arg_type_ids, *task.num_args); + UTVMDone(); + return 0; +} diff --git a/src/runtime/micro/device/utvm_runtime.h b/src/runtime/micro/device/utvm_runtime.h new file mode 100644 index 0000000000000..6803b956c46c4 --- /dev/null +++ b/src/runtime/micro/device/utvm_runtime.h @@ -0,0 +1,27 @@ +/*! + * Copyright (c) 2019 by Contributors + * \file utvm_runtime.h + * \brief utvm runtime headers + */ +#ifndef UTVM_RUNTIME_H_ +#define UTVM_RUNTIME_H_ + +#ifdef __cplusplus +extern "C" { +#endif +#include + +/*! + * \brief task structure for uTVM + */ +typedef struct { + int (*func)(void*, void*, int32_t); + void* args; + void* arg_type_ids; + int32_t* num_args; +} UTVMTask; + +#ifdef __cplusplus +} // TVM_EXTERN_C +#endif +#endif // UTVM_RUNTIME_H_ diff --git a/src/runtime/micro/host_low_level_device.cc b/src/runtime/micro/host_low_level_device.cc new file mode 100644 index 0000000000000..4bde88adc8310 --- /dev/null +++ b/src/runtime/micro/host_low_level_device.cc @@ -0,0 +1,50 @@ +/*! + * Copyright (c) 2019 by Contributors + * \file host_low_level_device.cc + * \brief emulated low-level micro device implementation on host machine + */ + +#include "low_level_device.h" + +namespace tvm { +namespace runtime { +/*! + * \brief emulated low-level device on host machine + */ +class HostLowLevelDevice final : public LowLevelDevice { + public: + /*! + * \brief constructor to initialize on-host memory region to act as device + * \param num_bytes size of the emulated on-device memory region + */ + HostLowLevelDevice(size_t num_bytes); + + /*! + * \brief destructor to deallocate on-host device region + */ + ~HostLowLevelDevice(); + + void Write(void* offset, + void* buf, + size_t num_bytes) final; + + void Read(void* offset, + void* buf, + size_t num_bytes) final; + + void Execute(void* func_addr, void* breakpoint) final; + + const void* base_addr() const final; + + private: + /*! \brief base address of the micro device memory region */ + void* base_addr_; + /*! \brief size of memory region */ + size_t size_; +}; + +const std::shared_ptr HostLowLevelDeviceCreate(size_t num_bytes) { + return nullptr; +} +} // namespace runtime +} // namespace tvm diff --git a/src/runtime/micro/low_level_device.h b/src/runtime/micro/low_level_device.h new file mode 100644 index 0000000000000..9cc80b9717b13 --- /dev/null +++ b/src/runtime/micro/low_level_device.h @@ -0,0 +1,69 @@ +/*! + * Copyright (c) 2019 by Contributors + * \file low_level_device.h + * \brief Abstract low-level micro device management + */ +#ifndef TVM_RUNTIME_LOW_LEVEL_DEVICE_H_ +#define TVM_RUNTIME_LOW_LEVEL_DEVICE_H_ + +#include +#include + +namespace tvm { +namespace runtime { +/*! + * \brief virtual interface for low-level micro device management + */ +class LowLevelDevice { + public: + /*! \brief virtual destructor */ + virtual ~LowLevelDevice() {} + + /*! + * \brief writes num_bytes from buffer to device memory at base_addr + offset + * \param offset on-device memory offset pointer to be written to + * \param buffer on-host buffer to be written + * \param num_bytes number of bytes to be written + */ + virtual void Write(void* offset, + void* buffer, + size_t num_bytes) = 0; + + /*! + * \brief reads num_bytes from device memory at base_addr + offset into buffer + * \param offset on-device memory offset pointer to be read from + * \param buffer on-host buffer to be read into + * \param num_bytes number of bytes to be read + */ + virtual void Read(void* offset, + void* buffer, + size_t num_bytes) = 0; + + /*! + * \brief starts execution of device at offset + * \param func_addr address of the init stub function + * \param breakpoint breakpoint at which to stop function execution + */ + virtual void Execute(void* func_addr, void* breakpoint) = 0; + + /*! + * \brief getter function for base_addr + * \return the base address of the device memory region + */ + virtual const void* base_addr() const = 0; +}; + +/*! + * \brief create a host low-level device + * \param num_bytes size of the memory region + */ +const std::shared_ptr HostLowLevelDeviceCreate(size_t num_bytes); + +/*! + * \brief connect to OpenOCD and create an OpenOCD low-level device + * \param port port of the OpenOCD server to connect to + */ +const std::shared_ptr OpenOCDLowLevelDeviceCreate(int port); +} // namespace runtime +} // namespace tvm +#endif // TVM_RUNTIME_LOW_LEVEL_DEVICE_H_ diff --git a/src/runtime/micro/micro_common.cc b/src/runtime/micro/micro_common.cc new file mode 100644 index 0000000000000..38de64ee79271 --- /dev/null +++ b/src/runtime/micro/micro_common.cc @@ -0,0 +1,53 @@ +/*! + * Copyright (c) 2019 by Contributors + * \file bin_util.cc + * \brief binary modification utilities + */ + +#include +#include +#include "micro_session.h" +#include "micro_common.h" + +namespace tvm { +namespace runtime { + +const char* SectionToString(SectionKind section) { + switch (section) { + case kText: return "text"; + case kData: return "data"; + case kBss: return "bss"; + case kArgs: return "args"; + case kStack: return "stack"; + case kHeap: return "heap"; + case kWorkspace: return "workspace"; + } +} + +// TODO: implement these in Python using PackedFunc + Registry +void* GetSymbol(std::unordered_map symbol_map, + std::string name, + void* base_addr) { + return nullptr; +} + +std::string RelocateBinarySections(std::string binary_name, + void* text, + void* data, + void* bss) { + return ""; +} + +std::string ReadSection(std::string binary_name, Section section) { + return ""; +} + +size_t GetSectionSize(std::string binary_name, Section section) { + return 0; +} + +std::unordered_map GetSymbolMap(std::string binary) { + return nullptr; +} +} // namespace runtime +} // namespace tvm diff --git a/src/runtime/micro/micro_common.h b/src/runtime/micro/micro_common.h new file mode 100644 index 0000000000000..99c88a4da6349 --- /dev/null +++ b/src/runtime/micro/micro_common.h @@ -0,0 +1,82 @@ +/*! + * Copyright (c) 2019 by Contributors + * \file micro_common.h + */ +#ifndef TVM_RUNTIME_MICRO_MICRO_COMMON_H_ +#define TVM_RUNTIME_MICRO_MICRO_COMMON_H_ + +#include +#include +#include "micro_session.h" + +namespace tvm { +namespace runtime { +/*! + * \brief enum of device memory region sections + */ +enum SectionKind : int { + kText = 0, + kData = 1, + kBss = 2, + kArgs = 3, + kStack = 4, + kHeap = 5, + kWorkspace = 6, +}; + +/*! + * \brief maps section enums to text + * \param section section type + * \return text form of the specified section + */ +const char* SectionToString(SectionKind section); + +/*! + * \brief get relative address of the symbol from the symbol map + * \param map of symbols to addresses + * \param name symbol name + * \param base_addr base address to obtain offset from + * \return address of the symbol relative to base_addr + */ +void* GetSymbol(std::unordered_map symbol_map, + std::string name, + void* base_addr); + +/*! + * \brief links binary by repositioning section addresses + * \param binary_name input binary filename + * \param text new text section address + * \param data new data section address + * \param bss new bss section address + * \return relocated binary file contents + */ +std::string RelocateBinarySections(std::string binary_name, + void* text, + void* data, + void* bss); + +/*! + * \brief reads section from binary file + * \param binary_name input binary filename + * \param section section type to be read + * \return contents of the section + */ +std::string ReadSection(std::string binary_name, SectionKind section); + +/*! + * \brief finds size of the section in the binary + * \param binary input binary contents + * \param section section type + * \return size of the section if it exists, 0 otherwise + */ +size_t GetSectionSize(std::string binary_name, SectionKind section); + +/*! + * \brief builds a map of symbol to address + * \param binary contents of the binary file + * \return map of symbols to their addresses + */ +std::unordered_map GetSymbolMap(std::string binary); +} // namespace runtime +} // namespace tvm +#endif // TVM_RUNTIME_MICRO_MICRO_COMMON_H_ diff --git a/src/runtime/micro/micro_device_api.cc b/src/runtime/micro/micro_device_api.cc new file mode 100644 index 0000000000000..5f6a02caae1a4 --- /dev/null +++ b/src/runtime/micro/micro_device_api.cc @@ -0,0 +1,75 @@ +/*! + * Copyright (c) 2019 by Contributors + * \file micro_device_api.cc + */ + +#include +#include +#include +#include "../workspace_pool.h" + +namespace tvm { +namespace runtime { +/*! + * \brief device API for uTVM micro devices + */ +class MicroDeviceAPI final : public DeviceAPI { + public: + void SetDevice(TVMContext ctx) final {} + + void GetAttr(TVMContext ctx, DeviceAttrKind kind, TVMRetValue* rv) final { + if (kind == kExist) { + *rv = 1; + } + } + + void* AllocDataSpace(TVMContext ctx, + size_t nbytes, + size_t alignment, + TVMType type_hint) final { + return nullptr; + } + + void FreeDataSpace(TVMContext ctx, void* ptr) final { + } + + void CopyDataFromTo(const void* from, + size_t from_offset, + void* to, + size_t to_offset, + size_t size, + TVMContext ctx_from, + TVMContext ctx_to, + TVMType type_hint, + TVMStreamHandle stream) final { + } + + void StreamSync(TVMContext ctx, TVMStreamHandle stream) final { + } + + void* AllocWorkspace(TVMContext ctx, size_t size, TVMType type_hint) final { + return nullptr; + } + + void FreeWorkspace(TVMContext ctx, void* data) final { + } + + /*! + * \brief obtain a global singleton of MicroDeviceAPI + * \return global shared pointer to MicroDeviceAPI + */ + static const std::shared_ptr& Global() { + static std::shared_ptr inst = + std::make_shared(); + return inst; + } +}; + +// register device that can be obtained from Python frontend +TVM_REGISTER_GLOBAL("device_api.micro_dev") +.set_body([](TVMArgs args, TVMRetValue* rv) { + DeviceAPI* ptr = MicroDeviceAPI::Global().get(); + *rv = static_cast(ptr); + }); +} // namespace runtime +} // namespace tvm diff --git a/src/runtime/micro/micro_module.cc b/src/runtime/micro/micro_module.cc new file mode 100644 index 0000000000000..503b7fd7b6624 --- /dev/null +++ b/src/runtime/micro/micro_module.cc @@ -0,0 +1,94 @@ +/*! +* Copyright (c) 2019 by Contributors +* \file micro_module.cc +*/ + +#include +#include +#include +#include +#include +#include "micro_session.h" +#include "low_level_device.h" + +namespace tvm { +namespace runtime { +/*! + * \brief module for uTVM micro devices + */ +class MicroModuleNode final : public ModuleNode { + public: + ~MicroModuleNode(); + + const char* type_key() const final { + return "micro"; + } + + PackedFunc GetFunction(const std::string& name, + const std::shared_ptr& sptr_to_self) final; + + /*! + * \brief initializes module by establishing device connection and loads binary + * \param binary name of the binary to be loaded + */ + void InitMicroModule(const std::string binary); + + /*! + * \brief runs selected function on the micro device + * \param func name of the function to be run + * \param args type-erased arguments passed to the function + */ + void RunFunction(std::string func, TVMArgs args); + + private: + /*! \brief loaded module text start address */ + void* text_start_; + /*! \brief loaded module data start address */ + void* data_start_; + /*! \brief loaded module bss start address */ + void* bss_start_; + /*! \brief size of module text section */ + size_t code_size_; + /*! \brief size of module data section */ + size_t data_size_; + /*! \brief size of module bss section */ + size_t bss_size_; + /*! \brief module binary */ + std::string binary_; + /*! \brief global session pointer */ + std::shared_ptr session_; + /*! \brief low-level device pointer */ + std::shared_ptr lldevice_; + /*! \brief symbol map to addresses */ + std::unordered_map symbol_map; +}; + +class MicroWrappedFunc { + public: + MicroWrappedFunc(MicroModuleNode* m, + const std::string& func_name, + void* func_addr) { + m_ = m; + func_name_ = func_name; + func_addr_ = func_addr; + } + + void operator()(TVMArgs args, TVMRetValue* rv) const { + } + + private: + // internal module + MicroModuleNode* m_; + // name of the function + std::string func_name_; + // address of the function to be called + void* func_addr_; +}; + +// TODO: register module load function +// register loadfile function to load module from Python frontend +TVM_REGISTER_GLOBAL("module.loadfile_micro_dev") +.set_body([](TVMArgs args, TVMRetValue* rv) { + }); +} // namespace runtime +} // namespace tvm diff --git a/src/runtime/micro/micro_session.cc b/src/runtime/micro/micro_session.cc new file mode 100644 index 0000000000000..b8654ad0c573b --- /dev/null +++ b/src/runtime/micro/micro_session.cc @@ -0,0 +1,23 @@ +/*! + * Copyright (c) 2019 by Contributors + * \file micro_session.cc + * \brief session to manage multiple micro modules + */ + +#include +#include +#include "micro_session.h" +#include "low_level_device.h" + +namespace tvm { +namespace runtime { +// TODO: create Python frontend for this +// initializes micro session and low-level device from Python frontend +TVM_REGISTER_GLOBAL("micro.init") +.set_body([](TVMArgs args, TVMRetValue* rv) { + // create global micro session + // setup either host or OpenOCD low-level device + // setup init stub + }); +} // namespace runtime +} // namespace tvm diff --git a/src/runtime/micro/micro_session.h b/src/runtime/micro/micro_session.h new file mode 100644 index 0000000000000..c1968c3bc02f8 --- /dev/null +++ b/src/runtime/micro/micro_session.h @@ -0,0 +1,182 @@ +/*! + * Copyright (c) 2019 by Contributors + * \file micro_session.h + */ +#ifndef TVM_RUNTIME_MICRO_MICRO_SESSION_H_ +#define TVM_RUNTIME_MICRO_MICRO_SESSION_H_ + +#include +#include +#include +#include +#include +#include +#include "low_level_device.h" +#include "allocator_stream.h" +#include "micro_common.h" +#include "device/utvm_runtime.h" + +namespace tvm { +namespace runtime { +/*! \brief number of bytes in each page */ +constexpr int kPageSize = 4096; + +/*! \brief memory offset at which text section starts */ +constexpr int kTextStart = 64; + +/*! \brief memory offset at which data section starts */ +constexpr int kDataStart = 50000; + +/*! \brief memory offset at which bss section starts */ +constexpr int kBssStart = 100000; + +/*! \brief memory offset at which args section starts */ +constexpr int kArgsStart = 150000; + +/*! \brief memory offset at which stack section starts */ +constexpr int kStackStart = 250000; + +/*! \brief memory offset at which heap section starts */ +constexpr int kHeapStart = 300000; + +/*! \brief memory offset at which workspace section starts */ +constexpr int kWorkspaceStart = 350000; + +/*! \brief total memory size */ +constexpr int kMemorySize = 409600; + +/*! + * \brief allocator for a on-device memory section + */ +class MicroSectionAllocator { + public: + /*! + * \brief constructor that specifies section boundaries + * \param section_start start address of the section + * \param section_end end address of the section (non inclusive) + */ + MicroSectionAllocator(void* section_start, void* section_end); + + /*! + * \brief memory allocator + * \param size size of allocated memory in bytes + * \return pointer to allocated memory region in section, nullptr if out of space + */ + void* Allocate(size_t size); + + /*! + * \brief free prior allocation from section + * \param type type of section to allocate in + * \param ptr pointer to allocated memory + */ + void Free(void* ptr); + + private: + /*! \brief start address of the section */ + void* section_start_; + /*! \brief end address of the section */ + void* section_end_; + /*! \brief end address of last allocation */ + void* section_max_; + /*! \brief allocation map for allocation sizes */ + std::unordered_map alloc_map_; +}; + +class MicroSession { + public: + /*! + * \brief destructor + */ + ~MicroSession(); + + /*! + * \brief get MicroSession global singleton + * \return pointer to the micro session global singleton + */ + static const MicroSession* Global(); + + /*! + * \brief allocate memory in section + * \param type type of section to allocate in + * \param size size of allocated memory in bytes + * \return pointer to allocated memory region in section, nullptr if out of space + */ + void* AllocateInSection(SectionKind type, size_t size); + + /*! + * \brief free prior allocation from section + * \param type type of section to allocate in + * \param ptr pointer to allocated memory + */ + void FreeInSection(SectionKind type, void* ptr); + + /*! + * \brief sets up init stub pointers and copies arguments for on-device execution + * \param func address of the function to be executed + * \param args args to the packed function + */ + void PushToExecQueue(void* func, TVMArgs args); + + /*! + * \brief returns low-level device pointer + * \note assumes low_level_device_ is initialized + */ + const std::shared_ptr low_level_device() const { + return low_level_device_; + } + + /*! + * \brief converts actual address to offset from base_addr + * \note assumes low_level_device_ is initialized + * \param addr address to be converted to offset + * \return offset from base_addr + */ + const void* GetOffset(void* addr) const { + return (void*) ((uint8_t*) addr - + (uint8_t*) low_level_device()->base_addr()); + } + + /*! + * \brief converts offset to actual address + * \note assumes low_level_device_ is initialized + * \param offset offset from base_addr + * \return on-device physical address + */ + const void* GetAddr(void* offset) const { + return (void*) ((uint8_t*) low_level_device()->base_addr() + + reinterpret_cast(offset)); + } + + private: + /*! \brief low-level device pointer */ + std::shared_ptr low_level_device_; + /*! \brief text section allocator */ + MicroSectionAllocator text_allocator_; + /*! \brief data section allocator */ + MicroSectionAllocator data_allocator_; + /*! \brief bss section allocator */ + MicroSectionAllocator bss_allocator_; + /*! \brief args section allocator */ + MicroSectionAllocator args_allocator_; + /*! \brief stack section allocator */ + MicroSectionAllocator stack_allocator_; + /*! \brief heap section allocator */ + MicroSectionAllocator heap_allocator_; + /*! \brief workspace section allocator */ + MicroSectionAllocator workspace_allocator_; + /*! \brief symbol map for init stub */ + std::unordered_map init_symbol_map_; + + /*! + * \brief sets up and loads init stub into the low-level device memory + */ + void SetupInitStub(); + + /*! + * \brief writes arguments to args section using allocator_stream + */ + void AllocateTVMArgs(TVMArgs args); +}; +} // namespace runtime +} // namespace tvm +#endif // TVM_RUNTIME_MICRO_MICRO_SESSION_H_ diff --git a/src/runtime/micro/openocd_low_level_device.cc b/src/runtime/micro/openocd_low_level_device.cc new file mode 100644 index 0000000000000..d192945825dad --- /dev/null +++ b/src/runtime/micro/openocd_low_level_device.cc @@ -0,0 +1,50 @@ +/*! + * Copyright (c) 2019 by Contributors + * \file openocd_low_level_device.cc + * \brief openocd low-level device to interface with micro devices over JTAG + */ + +#include "low_level_device.h" + +namespace tvm { +namespace runtime { +/*! + * \brief openocd low-level device for uTVM micro devices connected over JTAG + */ +class OpenOCDLowLevelDevice final : public LowLevelDevice { + public: + /*! + * \brief constructor to initialize connection to openocd device + * \param port port of the OpenOCD server to connect to + */ + OpenOCDLowLevelDevice(int port); + + /*! + * \brief destructor to close openocd device connection + */ + ~OpenOCDLowLevelDevice(); + + void Write(void* offset, + void* buf, + size_t num_bytes) final; + + void Read(void* offset, + void* buf, + size_t num_bytes) final; + + void Execute(void* func_addr, void* breakpoint) final; + + const void* base_addr() const final; + + private: + /*! \brief base address of the micro device memory region */ + void* base_addr_; + /*! \brief size of memory region */ + size_t size_; +}; + +const std::shared_ptr OpenOCDLowLevelDeviceCreate(int port) { + return nullptr; +} +} // namespace runtime +} // namespace tvm diff --git a/src/runtime/module.cc b/src/runtime/module.cc index cc0fd0922f93d..6e26553c14aaf 100644 --- a/src/runtime/module.cc +++ b/src/runtime/module.cc @@ -139,6 +139,8 @@ bool RuntimeEnabled(const std::string& target) { f_name = "device_api.rpc"; } else if (target == "vpi" || target == "verilog") { f_name = "device_api.vpi"; + } else if (target == "micro_dev") { + f_name = "device_api.micro_dev"; } else if (target.length() >= 5 && target.substr(0, 5) == "nvptx") { f_name = "device_api.gpu"; } else if (target.length() >= 4 && target.substr(0, 4) == "rocm") { diff --git a/tests/python/unittest/test_runtime_micro.py b/tests/python/unittest/test_runtime_micro.py new file mode 100644 index 0000000000000..8affc295dcbcf --- /dev/null +++ b/tests/python/unittest/test_runtime_micro.py @@ -0,0 +1,14 @@ +import tvm +import os +import logging +import time + +import numpy as np +from tvm.contrib import util + +# adds two arrays and stores result into third array +def test_micro_add(): + pass + +if __name__ == "__main__": + test_micro_add()