aboutsummaryrefslogtreecommitdiff
path: root/applications/message_process/src/message_process.cc
diff options
context:
space:
mode:
Diffstat (limited to 'applications/message_process/src/message_process.cc')
-rw-r--r--applications/message_process/src/message_process.cc214
1 files changed, 214 insertions, 0 deletions
diff --git a/applications/message_process/src/message_process.cc b/applications/message_process/src/message_process.cc
new file mode 100644
index 0000000..e61c648
--- /dev/null
+++ b/applications/message_process/src/message_process.cc
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2020 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 <message_process.hpp>
+
+#include <cstddef>
+#include <cstdio>
+
+namespace MessageProcess {
+
+QueueImpl::QueueImpl(ethosu_core_queue &queue) : queue(queue) {}
+
+bool QueueImpl::empty() const {
+ return queue.header.read == queue.header.write;
+}
+
+size_t QueueImpl::available() const {
+ size_t avail = queue.header.write - queue.header.read;
+
+ if (queue.header.read > queue.header.write) {
+ avail += queue.header.size;
+ }
+
+ return avail;
+}
+
+size_t QueueImpl::capacity() const {
+ return queue.header.size - available();
+}
+
+bool QueueImpl::read(uint8_t *dst, uint32_t length) {
+ const uint8_t *end = dst + length;
+ uint32_t rpos = queue.header.read;
+
+ if (length > available()) {
+ return false;
+ }
+
+ while (dst < end) {
+ *dst++ = queue.data[rpos];
+ rpos = (rpos + 1) % queue.header.size;
+ }
+
+ queue.header.read = rpos;
+
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
+ SCB_CleanDCache();
+#endif
+
+ return true;
+}
+
+bool QueueImpl::write(const Vec *vec, size_t length) {
+ size_t total = 0;
+
+ for (size_t i = 0; i < length; i++) {
+ total += vec[i].length;
+ }
+
+ if (total > capacity()) {
+ return false;
+ }
+
+ uint32_t wpos = queue.header.write;
+
+ for (size_t i = 0; i < length; i++) {
+ const uint8_t *src = reinterpret_cast<const uint8_t *>(vec[i].base);
+ const uint8_t *end = src + vec[i].length;
+
+ while (src < end) {
+ queue.data[wpos] = *src++;
+ wpos = (wpos + 1) % queue.header.size;
+ }
+ }
+
+ // Update the write position last
+ queue.header.write = wpos;
+
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
+ SCB_CleanDCache();
+#endif
+
+ // TODO replace with mailbox driver APIs
+ volatile uint32_t *set = reinterpret_cast<volatile uint32_t *>(0x41A00014);
+ *set = 0x1;
+
+ return true;
+}
+
+bool QueueImpl::write(const uint32_t type, const void *src, uint32_t length) {
+ ethosu_core_msg msg = {type, length};
+ Vec vec[2] = {{&msg, sizeof(msg)}, {src, length}};
+
+ return write(vec, 2);
+}
+
+MessageProcess::MessageProcess(ethosu_core_queue &in,
+ ethosu_core_queue &out,
+ InferenceProcess::InferenceProcess &inferenceProcess) :
+ queueIn(in),
+ queueOut(out), inferenceProcess(inferenceProcess) {}
+
+void MessageProcess::run() {
+ while (true) {
+ // Handle all messages in queue
+ while (handleMessage())
+ ;
+
+ // Wait for event
+ __WFE();
+ }
+}
+
+void MessageProcess::handleIrq() {
+ __SEV();
+}
+
+bool MessageProcess::handleMessage() {
+ ethosu_core_msg msg;
+ union {
+ ethosu_core_inference_req inferenceReq;
+ uint8_t data[1000];
+ } data;
+
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
+ SCB_InvalidateDCache();
+#endif
+
+ // Read msg header
+ if (!queueIn.read(msg)) {
+ return false;
+ }
+
+ printf("Message. type=%u, length=%u\n", msg.type, msg.length);
+
+ // Read payload
+ if (!queueIn.read(data.data, msg.length)) {
+ printf("Failed to read payload.\n");
+ return false;
+ }
+
+ switch (msg.type) {
+ case ETHOSU_CORE_MSG_PING:
+ printf("Ping\n");
+ sendPong();
+ break;
+ case ETHOSU_CORE_MSG_INFERENCE_REQ: {
+ std::memcpy(&data.inferenceReq, data.data, sizeof(data.data));
+
+ ethosu_core_inference_req &req = data.inferenceReq;
+
+ printf("InferenceReq. network={0x%x, %u}, ifm={0x%x, %u}, ofm={0x%x, %u}\n",
+ req.network.ptr,
+ req.network.size,
+ req.ifm.ptr,
+ req.ifm.size,
+ req.ofm.ptr,
+ req.ofm.size,
+ req.user_arg);
+
+ InferenceProcess::DataPtr networkModel(reinterpret_cast<void *>(req.network.ptr), req.network.size);
+ InferenceProcess::DataPtr ifm(reinterpret_cast<void *>(req.ifm.ptr), req.ifm.size);
+ InferenceProcess::DataPtr ofm(reinterpret_cast<void *>(req.ofm.ptr), req.ofm.size);
+ InferenceProcess::DataPtr expectedOutput;
+ InferenceProcess::InferenceJob job("job", networkModel, ifm, ofm, expectedOutput, -1);
+
+ bool failed = inferenceProcess.runJob(job);
+
+ sendInferenceRsp(data.inferenceReq.user_arg, job.output.size, failed);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return true;
+}
+
+void MessageProcess::sendPong() {
+ if (!queueOut.write(ETHOSU_CORE_MSG_PONG)) {
+ printf("Failed to write pong.\n");
+ }
+}
+
+void MessageProcess::sendInferenceRsp(uint64_t userArg, size_t ofmSize, bool failed) {
+ ethosu_core_inference_rsp rsp;
+
+ rsp.user_arg = userArg;
+ rsp.ofm_size = ofmSize;
+ rsp.status = failed ? ETHOSU_CORE_STATUS_ERROR : ETHOSU_CORE_STATUS_OK;
+
+ printf(
+ "Sending inference response. userArg=0x%llx, ofm_size=%u, status=%u\n", rsp.user_arg, rsp.ofm_size, rsp.status);
+
+ if (!queueOut.write(ETHOSU_CORE_MSG_INFERENCE_RSP, rsp)) {
+ printf("Failed to write inference.\n");
+ }
+}
+} // namespace MessageProcess