aboutsummaryrefslogtreecommitdiff
path: root/utils/ethosu_logd/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/ethosu_logd/main.cpp')
-rw-r--r--utils/ethosu_logd/main.cpp290
1 files changed, 290 insertions, 0 deletions
diff --git a/utils/ethosu_logd/main.cpp b/utils/ethosu_logd/main.cpp
new file mode 100644
index 0000000..d7ff1eb
--- /dev/null
+++ b/utils/ethosu_logd/main.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed 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
+ *
+ * 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.
+ */
+
+#include "dev_mem.hpp"
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <dirent.h>
+
+namespace {
+
+void help(const char *prog) {
+ std::cerr << "USAGE: " << prog << " [-h] [--address ADDRESS] [-c] [-C]" << std::endl << std::endl;
+ std::cerr << "positional argument:" << std::endl;
+ std::cerr << " -h, --help Show help message and exit" << std::endl;
+ std::cerr << " --address ADDRESS Address of ring buffer" << std::endl;
+ std::cerr << " -C Clear the ring buffer" << std::endl;
+ std::cerr << " -c Read and clear the ring buffer" << std::endl;
+}
+
+class Path {
+public:
+ Path(const std::string path) : path(path) {}
+
+ Path(const char *path) : path(path) {}
+
+ std::string string() const {
+ return path;
+ }
+
+ const char *c_str() const {
+ return path.c_str();
+ }
+
+ Path operator/(const std::string &other) const {
+ if (other.substr(0, 1) == "/") {
+ return Path(other);
+ } else {
+ return Path(path + "/" + other);
+ }
+ }
+
+ bool exists() const {
+ std::ifstream f = std::ifstream(path);
+ return !!f;
+ }
+
+ std::vector<Path> find(const std::string &name) const {
+ std::vector<Path> files;
+ find(*this, name, files);
+ return files;
+ }
+
+ Path parent() const {
+ return Path(path.substr(0, path.rfind("/")));
+ }
+
+private:
+ const std::string path;
+
+ static void find(const Path &path, const std::string &name, std::vector<Path> &files) {
+ DIR *dir = opendir(path.c_str());
+ if (dir == nullptr) {
+ throw EthosU::DevMem::Exception(std::string("Failed to open ") + path.string());
+ }
+
+ const dirent *dentry;
+ while ((dentry = readdir(dir)) != nullptr) {
+ const std::string dname = dentry->d_name;
+ const Path pathname = path / dname;
+
+ // Add path to list if it matches 'name'
+ if (dname == name) {
+ files.push_back(pathname);
+ }
+
+ // Call 'find' recursively for directories
+ if (dname != "." && dname != ".." && dentry->d_type == DT_DIR) {
+ find(pathname, name, files);
+ }
+ }
+
+ closedir(dir);
+ }
+};
+
+bool grep(const Path &path, const std::string &match) {
+ std::ifstream ifs(path.c_str(), std::ios_base::binary);
+ std::string content = std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
+ return content.find(match) != std::string::npos;
+}
+
+class DTS {
+public:
+ DTS(const Path &path) : path(path) {}
+
+ void getRegByName(const std::string &name, uintptr_t &address, size_t &size) const {
+ size_t index = 0;
+ for (const auto &n : getString("reg-names")) {
+ if (n == name) {
+ getRegByIndex(index, address, size);
+ return;
+ }
+
+ index++;
+ }
+
+ throw EthosU::DevMem::Exception(std::string("Failed to find 'reg-name' ") + name);
+ }
+
+ void getRegByIndex(const size_t index, uintptr_t &address, size_t &size) const {
+ size_t addressCell = getAddressCells();
+ size_t sizeCell = getSizeCells();
+ size_t offset = index * (addressCell + sizeCell) * 4;
+
+ address = getInt("reg", offset, addressCell * 4);
+ size = getInt("reg", offset + addressCell * 4, sizeCell * 4);
+ }
+
+private:
+ const Path path;
+
+ size_t getAddressCells() const {
+ const Path p = path / "#address-cells";
+ if (!p.exists()) {
+ return 2;
+ }
+
+ return getInt(p.string(), 0, 4);
+ }
+
+ size_t getSizeCells() const {
+ const Path p = path / "#size-cells";
+ if (!p.exists()) {
+ return 2;
+ }
+
+ return getInt(p.string(), 0, 4);
+ }
+
+ std::vector<char> getProperty(const std::string &name) const {
+ const Path propertyPath = path / name;
+ std::ifstream ifs(propertyPath.c_str(), std::ios_base::binary);
+ std::vector<char> content =
+ std::vector<char>(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
+ return content;
+ }
+
+ std::vector<std::string> getString(const std::string &name) const {
+ std::vector<char> property = getProperty(name);
+ std::vector<std::string> names;
+
+ for (std::vector<char>::iterator end, it = property.begin();
+ (end = std::find(it, property.end(), '\0')) != property.end();
+ it = end + 1) {
+ names.push_back(std::string(it, end));
+ }
+
+ return names;
+ }
+
+ uint64_t getInt(const std::string &name, const size_t offset, const size_t size) const {
+ const std::vector<char> property = getProperty(name);
+
+ switch (size) {
+ case 1:
+ return toCpu<uint8_t>(&property[offset]);
+ case 2:
+ return toCpu<uint16_t>(&property[offset]);
+ case 4:
+ return toCpu<uint32_t>(&property[offset]);
+ case 8:
+ return toCpu<uint64_t>(&property[offset]);
+ default:
+ throw EthosU::DevMem::Exception("Illegal integer size");
+ }
+ }
+
+ static constexpr bool isBigEndian() {
+ int d = 0x12345678;
+ return (d & 0xf) == 1;
+ }
+
+ template <typename T>
+ static T toCpu(const char *src) {
+ T dst;
+ char *d = reinterpret_cast<char *>(&dst);
+
+ if (isBigEndian()) {
+ for (size_t i = 0; i < sizeof(T); i++) {
+ d[i] = src[i];
+ }
+ } else {
+ for (size_t i = 0; i < sizeof(T); i++) {
+ d[i] = src[sizeof(T) - 1 - i];
+ }
+ }
+
+ return dst;
+ }
+};
+
+void getAddressSizeFromDtb(uintptr_t &address, size_t &size) {
+ // This is the file system path to the device tree
+ const Path devtree = "/sys/firmware/devicetree/base";
+
+ // Search device tree for <path>/**/compatible
+ for (const auto &path : devtree.find("compatible")) {
+ // Grep for "ethosu" in 'compatible'
+ if (grep(path, "arm,ethosu")) {
+ DTS dts(path.parent());
+
+ dts.getRegByName("print_queue", address, size);
+ return;
+ }
+ }
+
+ throw EthosU::DevMem::Exception("Could not find Ethos-U device tree entry with reg-name 'print_queue'");
+}
+
+} // namespace
+
+int main(int argc, char *argv[]) {
+ try {
+ uintptr_t address = 0;
+ size_t size = 0;
+ bool clearBefore = false;
+ bool clearAfter = false;
+
+ for (int i = 1; i < argc; i++) {
+ std::string arg = argv[i];
+
+ if (arg == "--address") {
+ address = std::stol(argv[++i], nullptr, 0);
+ } else if (arg == "-c") {
+ clearAfter = true;
+ } else if (arg == "-C") {
+ clearBefore = true;
+ } else if (arg == "-h" || arg == "--help") {
+ help(argv[0]);
+ ::exit(0);
+ } else {
+ std::cerr << "Illegal argument '" + arg + "'" << std::endl;
+ help(argv[0]);
+ ::exit(1);
+ }
+ }
+
+ if (address == 0) {
+ getAddressSizeFromDtb(address, size);
+ }
+
+ EthosU::DevMem::Log log(address, size);
+
+ if (clearBefore) {
+ log.clear();
+ }
+
+ log.print();
+
+ if (clearAfter) {
+ log.clear();
+ }
+ } catch (std::exception &e) {
+ printf("Error: %s\n", e.what());
+ return 1;
+ }
+
+ return 0;
+}