Skip to content

Commit

Permalink
[Hardware][Verilator] Integrating and simulating hardware accelerator…
Browse files Browse the repository at this point in the history
…s in TVM (apache#6971)

* add files

* update interface

* update

* fix comment

* fix fmt

* remove widget repo

* remove
  • Loading branch information
vegaluisjose authored and trevor-m committed Dec 4, 2020
1 parent abd91ba commit 61b2a14
Show file tree
Hide file tree
Showing 7 changed files with 346 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions cmake/config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
27 changes: 27 additions & 0 deletions cmake/modules/contrib/Verilator.cmake
Original file line number Diff line number Diff line change
@@ -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()

100 changes: 100 additions & 0 deletions src/relay/backend/contrib/verilator/codegen.cc
Original file line number Diff line number Diff line change
@@ -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 <tvm/relay/attrs/nn.h>
#include <tvm/relay/expr_functor.h>
#include <tvm/relay/transform.h>
#include <tvm/relay/type.h>
#include <tvm/runtime/module.h>
#include <tvm/runtime/registry.h>

#include <fstream>
#include <numeric>
#include <sstream>

#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<JSONGraphNodeEntry> VisitExpr_(const CallNode* cn) override {
Expr expr = GetRef<Expr>(cn);
std::string name;
const CallNode* call = cn;
if (const auto* op_node = cn->op.as<OpNode>()) {
name = op_node->name;
} else {
LOG(FATAL) << "Verilator JSON runtime does not support calls to " << cn->op->GetTypeKey();
}

std::vector<JSONGraphNodeEntry> inputs;
for (const auto& arg : cn->args) {
auto res = VisitExpr(arg);
inputs.insert(inputs.end(), res.begin(), res.end());
}
auto node = std::make_shared<JSONGraphNode>(name, /* name_ */
"kernel", /* op_type_ */
inputs, 1 /* num_outputs_ */);
SetCallNodeAttribute(node, call);
return AddNode(node, GetRef<Expr>(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<FunctionNode>());
auto func = Downcast<Function>(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
57 changes: 57 additions & 0 deletions src/runtime/contrib/verilator/verilator_device.h
Original file line number Diff line number Diff line change
@@ -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 <tvm/runtime/c_runtime_api.h>

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_
42 changes: 42 additions & 0 deletions src/runtime/contrib/verilator/verilator_kernel.h
Original file line number Diff line number Diff line change
@@ -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 <tvm/runtime/c_runtime_api.h>

#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_
116 changes: 116 additions & 0 deletions src/runtime/contrib/verilator/verilator_runtime.cc
Original file line number Diff line number Diff line change
@@ -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 <tvm/runtime/ndarray.h>
#include <tvm/runtime/registry.h>

#include <cstddef>
#include <string>
#include <vector>

#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<String> const_names)
: JSONRuntimeBase(symbol_name, graph_json, const_names) {}

const char* type_key() const { return "verilator_json"; }

void Init(const Array<NDArray>& 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<int*> in_ptr;
std::vector<int*> out_ptr;
for (size_t i = 0; i < input_nodes_.size(); ++i) {
uint32_t eid = EntryID(input_nodes_[i], 0);
int* data = static_cast<int*>(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<int*>(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<String>& const_names) {
auto n = make_object<VerilatorJSONRuntime>(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<VerilatorJSONRuntime>);

} // namespace contrib
} // namespace runtime
} // namespace tvm

0 comments on commit 61b2a14

Please sign in to comment.