From 61b2a14130b5c7ad0a6c9b90ed881f99377a2d16 Mon Sep 17 00:00:00 2001 From: Luis Vega Date: Sat, 28 Nov 2020 20:01:16 -0800 Subject: [PATCH] [Hardware][Verilator] Integrating and simulating hardware accelerators in TVM (#6971) * add files * update interface * update * fix comment * fix fmt * remove widget repo * remove --- CMakeLists.txt | 1 + cmake/config.cmake | 3 + cmake/modules/contrib/Verilator.cmake | 27 ++++ .../backend/contrib/verilator/codegen.cc | 100 +++++++++++++++ .../contrib/verilator/verilator_device.h | 57 +++++++++ .../contrib/verilator/verilator_kernel.h | 42 +++++++ .../contrib/verilator/verilator_runtime.cc | 116 ++++++++++++++++++ 7 files changed, 346 insertions(+) create mode 100644 cmake/modules/contrib/Verilator.cmake create mode 100644 src/relay/backend/contrib/verilator/codegen.cc create mode 100644 src/runtime/contrib/verilator/verilator_device.h create mode 100644 src/runtime/contrib/verilator/verilator_kernel.h create mode 100644 src/runtime/contrib/verilator/verilator_runtime.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c1ff7035d62..8fe416e9de93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -369,6 +369,7 @@ include(cmake/modules/contrib/ONNX.cmake) include(cmake/modules/contrib/ArmComputeLib.cmake) include(cmake/modules/contrib/TensorRT.cmake) include(cmake/modules/contrib/VitisAI.cmake) +include(cmake/modules/contrib/Verilator.cmake) include(cmake/modules/Git.cmake) include(cmake/modules/LibInfo.cmake) include(cmake/modules/RustExt.cmake) diff --git a/cmake/config.cmake b/cmake/config.cmake index 8ed06b26de5e..0080e239f16d 100644 --- a/cmake/config.cmake +++ b/cmake/config.cmake @@ -236,6 +236,9 @@ set(USE_TENSORRT_RUNTIME OFF) # Whether use VITIS-AI codegen set(USE_VITIS_AI OFF) +# Build Verilator codegen and runtime, example located in 3rdparty/hw-widgets +set(USE_VERILATOR_HW OFF) + # Build ANTLR parser for Relay text format # Possible values: # - ON: enable ANTLR by searching default locations (cmake find_program for antlr4 and /usr/local for jar) diff --git a/cmake/modules/contrib/Verilator.cmake b/cmake/modules/contrib/Verilator.cmake new file mode 100644 index 000000000000..907944706a82 --- /dev/null +++ b/cmake/modules/contrib/Verilator.cmake @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +if(USE_VERILATOR_HW STREQUAL "ON") + file(GLOB VERILATOR_RELAY_CONTRIB_SRC src/relay/backend/contrib/verilator/codegen.cc) + list(APPEND COMPILER_SRCS ${VERILATOR_RELAY_CONTRIB_SRC}) + list(APPEND COMPILER_SRCS ${JSON_RELAY_CONTRIB_SRC}) + find_library(EXTERN_LIBRARY_VERILATOR NAMES verilator PATHS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/hw-widgets) + list(APPEND TVM_RUNTIME_LINKER_LIBS ${EXTERN_LIBRARY_VERILATOR}) + file(GLOB VERILATOR_CONTRIB_SRC src/runtime/contrib/verilator/verilator_runtime.cc) + list(APPEND RUNTIME_SRCS ${VERILATOR_CONTRIB_SRC}) +endif() + diff --git a/src/relay/backend/contrib/verilator/codegen.cc b/src/relay/backend/contrib/verilator/codegen.cc new file mode 100644 index 000000000000..4124fa2459d6 --- /dev/null +++ b/src/relay/backend/contrib/verilator/codegen.cc @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * \file src/relay/backend/contrib/verilator/codegen.cc + * \brief Implementation of Verilator codegen APIs. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../../../../runtime/contrib/json/json_node.h" +#include "../../utils.h" +#include "../codegen_json/codegen_json.h" + +namespace tvm { +namespace relay { +namespace contrib { + +using namespace backend; + +class VerilatorJSONSerializer : public backend::contrib::JSONSerializer { + using JSONGraphNode = tvm::runtime::json::JSONGraphNode; + using JSONGraphNodeEntry = tvm::runtime::json::JSONGraphNodeEntry; + + public: + VerilatorJSONSerializer(const std::string& symbol, const Expr& expr) + : JSONSerializer(symbol, expr) {} + + std::vector VisitExpr_(const CallNode* cn) override { + Expr expr = GetRef(cn); + std::string name; + const CallNode* call = cn; + if (const auto* op_node = cn->op.as()) { + name = op_node->name; + } else { + LOG(FATAL) << "Verilator JSON runtime does not support calls to " << cn->op->GetTypeKey(); + } + + std::vector inputs; + for (const auto& arg : cn->args) { + auto res = VisitExpr(arg); + inputs.insert(inputs.end(), res.begin(), res.end()); + } + auto node = std::make_shared(name, /* name_ */ + "kernel", /* op_type_ */ + inputs, 1 /* num_outputs_ */); + SetCallNodeAttribute(node, call); + return AddNode(node, GetRef(cn)); + } +}; + +/*! + * \brief The external compiler/codegen tool. It takes a Relay expression/module and + * compile it into a runtime module. + */ +runtime::Module VerilatorCompiler(const ObjectRef& ref) { + CHECK(ref->IsInstance()); + auto func = Downcast(ref); + auto func_name = GetExtSymbol(func); + VerilatorJSONSerializer serializer(func_name, func); + serializer.serialize(); + std::string graph_json = serializer.GetJSON(); + auto params = serializer.GetParams(); + + const auto* pf = runtime::Registry::Get("runtime.VerilatorJSONRuntimeCreate"); + CHECK(pf != nullptr) << "Cannot find JSON runtime module to create"; + auto mod = (*pf)(func_name, graph_json, params); + return mod; +} + +TVM_REGISTER_GLOBAL("relay.ext.verilator").set_body_typed(VerilatorCompiler); + +} // namespace contrib +} // namespace relay +} // namespace tvm diff --git a/src/runtime/contrib/verilator/verilator_device.h b/src/runtime/contrib/verilator/verilator_device.h new file mode 100644 index 000000000000..acd91a53bcff --- /dev/null +++ b/src/runtime/contrib/verilator/verilator_device.h @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * \file src/runtime/contrib/verilator/verilator_device.h + * \brief Use external verilator device. + */ + +#ifndef TVM_RUNTIME_CONTRIB_VERILATOR_VERILATOR_DEVICE_H_ +#define TVM_RUNTIME_CONTRIB_VERILATOR_VERILATOR_DEVICE_H_ + +#include + +namespace tvm { +namespace runtime { +namespace contrib { + +typedef void* VerilatorHandle; + +/* allocate Verilator object */ +extern "C" TVM_DLL VerilatorHandle VerilatorAlloc(); + +/* deallocate Verilator object */ +extern "C" TVM_DLL void VerilatorDealloc(VerilatorHandle handle); + +/* read Verilator register or memory */ +extern "C" TVM_DLL int VerilatorRead(VerilatorHandle handle, int id, int addr); + +/* write Verilator register or memory */ +extern "C" TVM_DLL void VerilatorWrite(VerilatorHandle handle, int id, int addr, int value); + +/* reset Verilator for n clock cycles */ +extern "C" TVM_DLL void VerilatorReset(VerilatorHandle handle, int n); + +/* run Verilator for n clock cycles */ +extern "C" TVM_DLL void VerilatorRun(VerilatorHandle handle, int n); + +} // namespace contrib +} // namespace runtime +} // namespace tvm +#endif // TVM_RUNTIME_CONTRIB_VERILATOR_VERILATOR_DEVICE_H_ diff --git a/src/runtime/contrib/verilator/verilator_kernel.h b/src/runtime/contrib/verilator/verilator_kernel.h new file mode 100644 index 000000000000..f62097c0d795 --- /dev/null +++ b/src/runtime/contrib/verilator/verilator_kernel.h @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * \file src/runtime/contrib/verilator/verilator_kernel.h + * \brief Use external verilator library kernels. + */ + +#ifndef TVM_RUNTIME_CONTRIB_VERILATOR_VERILATOR_KERNEL_H_ +#define TVM_RUNTIME_CONTRIB_VERILATOR_VERILATOR_KERNEL_H_ + +#include + +#include "verilator_device.h" + +namespace tvm { +namespace runtime { +namespace contrib { + +extern "C" TVM_DLL void verilator_add(VerilatorHandle handle, int* data, int* weight, int* out, + int p_h_, int p_w_); + +} // namespace contrib +} // namespace runtime +} // namespace tvm +#endif // TVM_RUNTIME_CONTRIB_VERILATOR_VERILATOR_KERNEL_H_ diff --git a/src/runtime/contrib/verilator/verilator_runtime.cc b/src/runtime/contrib/verilator/verilator_runtime.cc new file mode 100644 index 000000000000..a44faf6d3274 --- /dev/null +++ b/src/runtime/contrib/verilator/verilator_runtime.cc @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * \file src/runtime/contrib/verilator/verilator_runtime.cc + * \brief A simple JSON runtime for Verilator. + */ + +#include +#include + +#include +#include +#include + +#include "../json/json_node.h" +#include "../json/json_runtime.h" +#include "verilator_device.h" +#include "verilator_kernel.h" + +namespace tvm { +namespace runtime { +namespace contrib { + +using namespace tvm::runtime; +using namespace tvm::runtime::json; + +class VerilatorJSONRuntime : public JSONRuntimeBase { + public: + VerilatorJSONRuntime(const std::string& symbol_name, const std::string& graph_json, + const Array const_names) + : JSONRuntimeBase(symbol_name, graph_json, const_names) {} + + const char* type_key() const { return "verilator_json"; } + + void Init(const Array& consts) override { + BuildEngine(); + + CHECK_EQ(consts.size(), const_idx_.size()) + << "The number of input constants must match the number of required."; + + // Setup constants entries for weights. + SetupConstants(consts); + } + + void Run() override { + std::vector in_ptr; + std::vector out_ptr; + for (size_t i = 0; i < input_nodes_.size(); ++i) { + uint32_t eid = EntryID(input_nodes_[i], 0); + int* data = static_cast(data_entry_[eid]->data); + in_ptr.push_back(data); + } + for (size_t i = 0; i < outputs_.size(); ++i) { + uint32_t eid = EntryID(outputs_[i]); + int* data = static_cast(data_entry_[eid]->data); + out_ptr.push_back(data); + } + for (size_t nid = 0; nid < nodes_.size(); ++nid) { + const auto& node = nodes_[nid]; + if (node.GetOpType() == "kernel") { + CHECK_EQ(node.GetOpType(), "kernel"); + auto op_name = node.GetOpName(); + if ("add" == op_name) { + auto entry = node.GetInputs()[0]; + auto shape = nodes_[entry.id_].GetOpShape()[entry.index_]; + verilator_add(device_, in_ptr[0], in_ptr[1], out_ptr[0], shape[0], shape[1]); + } else { + LOG(FATAL) << "Unsupported op: " << op_name; + } + } + } + } + + private: + void BuildEngine() { + device_ = VerilatorAlloc(); + // reset for 10 cycles + VerilatorReset(device_, 10); + } + + /* The verilator handle. */ + VerilatorHandle device_{nullptr}; +}; + +runtime::Module VerilatorJSONRuntimeCreate(String symbol_name, String graph_json, + const Array& const_names) { + auto n = make_object(symbol_name, graph_json, const_names); + return runtime::Module(n); +} + +TVM_REGISTER_GLOBAL("runtime.VerilatorJSONRuntimeCreate") + .set_body_typed(VerilatorJSONRuntimeCreate); + +TVM_REGISTER_GLOBAL("runtime.module.loadbinary_verilator_json") + .set_body_typed(JSONRuntimeBase::LoadFromBinary); + +} // namespace contrib +} // namespace runtime +} // namespace tvm