aboutsummaryrefslogtreecommitdiff
path: root/applications/driver_unit_tests/command_stream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'applications/driver_unit_tests/command_stream.cpp')
-rw-r--r--applications/driver_unit_tests/command_stream.cpp179
1 files changed, 179 insertions, 0 deletions
diff --git a/applications/driver_unit_tests/command_stream.cpp b/applications/driver_unit_tests/command_stream.cpp
new file mode 100644
index 0000000..07f7f22
--- /dev/null
+++ b/applications/driver_unit_tests/command_stream.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+/****************************************************************************
+ * Includes
+ ****************************************************************************/
+
+#include "command_stream.hpp"
+
+#include <inttypes.h>
+#include <stdio.h>
+
+using namespace std;
+
+namespace EthosU {
+namespace CommandStream {
+
+/****************************************************************************
+ * DataPointer
+ ****************************************************************************/
+
+DataPointer::DataPointer() : data(nullptr), size(0) {}
+
+DataPointer::DataPointer(const char *_data, size_t _size) : data(_data), size(_size) {}
+
+bool DataPointer::operator!=(const DataPointer &other) {
+ if (size != other.size) {
+ return true;
+ }
+
+ for (size_t i = 0; i < size; i++) {
+ if (data[i] != other.data[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/****************************************************************************
+ * PmuConfig
+ ****************************************************************************/
+
+Pmu::Pmu(ethosu_driver *_drv, const PmuEvents &_config) :
+ drv(_drv),
+ config(_config)
+{
+ // Enable PMU block
+ ETHOSU_PMU_Enable_v2(drv);
+
+ // Enable cycle counter
+ ETHOSU_PMU_CNTR_Enable_v2(drv, ETHOSU_PMU_CCNT_Msk);
+
+ // Configure event types
+ for (size_t i = 0; i < config.size(); i++) {
+ ETHOSU_PMU_Set_EVTYPER_v2(drv, i, config[i]);
+ ETHOSU_PMU_CNTR_Enable_v2(drv, 1 << i);
+ }
+}
+
+void Pmu::clear() {
+ ETHOSU_PMU_CYCCNT_Reset_v2(drv);
+ ETHOSU_PMU_EVCNTR_ALL_Reset_v2(drv);
+}
+
+void Pmu::print() {
+ printf("PMU={cycleCount=%llu, events=[%" PRIu32 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 "]}\n",
+ ETHOSU_PMU_Get_CCNTR_v2(drv),
+ ETHOSU_PMU_Get_EVCNTR_v2(drv, 0),
+ ETHOSU_PMU_Get_EVCNTR_v2(drv, 1),
+ ETHOSU_PMU_Get_EVCNTR_v2(drv, 2),
+ ETHOSU_PMU_Get_EVCNTR_v2(drv, 3));
+}
+
+uint64_t Pmu::getCycleCount() const {
+ return ETHOSU_PMU_Get_CCNTR_v2(drv);
+}
+
+uint32_t Pmu::getEventCount(size_t index) const {
+ return ETHOSU_PMU_Get_EVCNTR_v2(drv, index);
+}
+
+/****************************************************************************
+ * CommandStream
+ ****************************************************************************/
+
+CommandStream::CommandStream(const DataPointer &_commandStream,
+ const BasePointers &_basePointers,
+ const PmuEvents &_pmuEvents) :
+ drv(ethosu_reserve_driver()),
+ commandStream(_commandStream),
+ basePointers(_basePointers),
+ pmu(drv, _pmuEvents)
+{
+ // Disable clock gating, else the NPU PMU will be clock gated and report too few cycles
+ ethosu_set_clock_and_power(&drv->dev, ETHOSU_CLOCK_Q_DISABLE, ETHOSU_POWER_Q_DISABLE);
+
+ // Use simplified driver setup
+ ethosu_set_power_mode_v2(drv, true);
+}
+
+CommandStream::~CommandStream() {
+ ethosu_set_power_mode_v2(drv, false);
+ ethosu_release_driver(drv);
+}
+
+int CommandStream::run(size_t repeat) {
+ // Base pointer array
+ uint64_t baseAddress[ETHOSU_DRIVER_BASEP_INDEXES];
+ size_t baseAddressSize[ETHOSU_DRIVER_BASEP_INDEXES];
+ for (size_t i = 0; i < ETHOSU_DRIVER_BASEP_INDEXES; i++) {
+ baseAddress[i] = reinterpret_cast<uint64_t>(basePointers[i].data);
+ baseAddressSize[i] = reinterpret_cast<size_t>(basePointers[i].size);
+ }
+
+ while (repeat-- > 0) {
+ int error = ethosu_invoke_v3(drv, commandStream.data, commandStream.size, baseAddress, baseAddressSize, ETHOSU_DRIVER_BASEP_INDEXES);
+
+ if (error != 0) {
+ printf("Inference failed. error=%d\n", error);
+ return 1;
+ }
+
+ // Wait for interrupt
+ while (true) {
+ uint16_t status;
+ ethosu_get_status_mask(&drv->dev, &status);
+
+ // Return if NPU raise error status
+ if (status & 0xcc) {
+ printf("Job failed with error. status=0x%08x\n", status);
+ return 1;
+ }
+
+ // Break loop if job is no longer running
+ if ((status & 1) == 0) {
+ break;
+ }
+
+ // Sleep waiting on interrupt
+ __WFI();
+ }
+ }
+
+ return 0;
+}
+
+DataPointer &CommandStream::getCommandStream()
+{
+ return commandStream;
+}
+
+BasePointers &CommandStream::getBasePointers()
+{
+ return basePointers;
+}
+
+Pmu &CommandStream::getPmu()
+{
+ return pmu;
+}
+
+}; // namespace CommandStream
+}; // namespace EthosU