blob: b201f32286097efd28682b8e47d72c1021ca85cb [file] [log] [blame]
Kristofer Jonsson641c0912020-08-31 11:34:14 +02001/*
2 * Copyright (c) 2020 Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#include <message_process.hpp>
20
21#include <cstddef>
22#include <cstdio>
Kristofer Jonsson25480142020-09-03 12:35:21 +020023#include <cstring>
Kristofer Jonsson641c0912020-08-31 11:34:14 +020024
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +020025using namespace std;
26using namespace InferenceProcess;
27
Kristofer Jonsson641c0912020-08-31 11:34:14 +020028namespace MessageProcess {
29
30QueueImpl::QueueImpl(ethosu_core_queue &queue) : queue(queue) {}
31
32bool QueueImpl::empty() const {
33 return queue.header.read == queue.header.write;
34}
35
36size_t QueueImpl::available() const {
37 size_t avail = queue.header.write - queue.header.read;
38
39 if (queue.header.read > queue.header.write) {
40 avail += queue.header.size;
41 }
42
43 return avail;
44}
45
46size_t QueueImpl::capacity() const {
47 return queue.header.size - available();
48}
49
50bool QueueImpl::read(uint8_t *dst, uint32_t length) {
51 const uint8_t *end = dst + length;
52 uint32_t rpos = queue.header.read;
53
54 if (length > available()) {
55 return false;
56 }
57
58 while (dst < end) {
59 *dst++ = queue.data[rpos];
60 rpos = (rpos + 1) % queue.header.size;
61 }
62
63 queue.header.read = rpos;
64
65#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
66 SCB_CleanDCache();
67#endif
68
69 return true;
70}
71
72bool QueueImpl::write(const Vec *vec, size_t length) {
73 size_t total = 0;
74
75 for (size_t i = 0; i < length; i++) {
76 total += vec[i].length;
77 }
78
79 if (total > capacity()) {
80 return false;
81 }
82
83 uint32_t wpos = queue.header.write;
84
85 for (size_t i = 0; i < length; i++) {
86 const uint8_t *src = reinterpret_cast<const uint8_t *>(vec[i].base);
87 const uint8_t *end = src + vec[i].length;
88
89 while (src < end) {
90 queue.data[wpos] = *src++;
91 wpos = (wpos + 1) % queue.header.size;
92 }
93 }
94
95 // Update the write position last
96 queue.header.write = wpos;
97
98#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
99 SCB_CleanDCache();
100#endif
101
102 // TODO replace with mailbox driver APIs
103 volatile uint32_t *set = reinterpret_cast<volatile uint32_t *>(0x41A00014);
104 *set = 0x1;
105
106 return true;
107}
108
109bool QueueImpl::write(const uint32_t type, const void *src, uint32_t length) {
110 ethosu_core_msg msg = {type, length};
111 Vec vec[2] = {{&msg, sizeof(msg)}, {src, length}};
112
113 return write(vec, 2);
114}
115
116MessageProcess::MessageProcess(ethosu_core_queue &in,
117 ethosu_core_queue &out,
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200118 ::InferenceProcess::InferenceProcess &inferenceProcess) :
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200119 queueIn(in),
120 queueOut(out), inferenceProcess(inferenceProcess) {}
121
122void MessageProcess::run() {
123 while (true) {
124 // Handle all messages in queue
125 while (handleMessage())
126 ;
127
128 // Wait for event
129 __WFE();
130 }
131}
132
133void MessageProcess::handleIrq() {
134 __SEV();
135}
136
137bool MessageProcess::handleMessage() {
138 ethosu_core_msg msg;
139 union {
140 ethosu_core_inference_req inferenceReq;
141 uint8_t data[1000];
142 } data;
143
144#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
145 SCB_InvalidateDCache();
146#endif
147
148 // Read msg header
149 if (!queueIn.read(msg)) {
150 return false;
151 }
152
153 printf("Message. type=%u, length=%u\n", msg.type, msg.length);
154
155 // Read payload
156 if (!queueIn.read(data.data, msg.length)) {
157 printf("Failed to read payload.\n");
158 return false;
159 }
160
161 switch (msg.type) {
162 case ETHOSU_CORE_MSG_PING:
163 printf("Ping\n");
164 sendPong();
165 break;
166 case ETHOSU_CORE_MSG_INFERENCE_REQ: {
167 std::memcpy(&data.inferenceReq, data.data, sizeof(data.data));
168
169 ethosu_core_inference_req &req = data.inferenceReq;
170
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200171 printf("InferenceReq. user_arg=0x%x, network={0x%x, %u}", req.user_arg, req.network.ptr, req.network.size);
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200172
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200173 printf(", ifm_count=%u, ifm=[", req.ifm_count);
174 for (uint32_t i = 0; i < req.ifm_count; ++i) {
175 if (i > 0) {
176 printf(", ");
177 }
178
179 printf("{0x%x, %u}", req.ifm[i].ptr, req.ifm[i].size);
180 }
181 printf("]");
182
183 printf(", ofm_count=%u, ofm=[", req.ofm_count);
184 for (uint32_t i = 0; i < req.ofm_count; ++i) {
185 if (i > 0) {
186 printf(", ");
187 }
188
189 printf("{0x%x, %u}", req.ofm[i].ptr, req.ofm[i].size);
190 }
191 printf("]\n");
192
193 DataPtr networkModel(reinterpret_cast<void *>(req.network.ptr), req.network.size);
194
195 vector<DataPtr> ifm;
196 for (uint32_t i = 0; i < req.ifm_count; ++i) {
197 ifm.push_back(DataPtr(reinterpret_cast<void *>(req.ifm[i].ptr), req.ifm[i].size));
198 }
199
200 vector<DataPtr> ofm;
201 for (uint32_t i = 0; i < req.ofm_count; ++i) {
202 ofm.push_back(DataPtr(reinterpret_cast<void *>(req.ofm[i].ptr), req.ofm[i].size));
203 }
204
205 vector<DataPtr> expectedOutput;
206
207 InferenceJob job("job", networkModel, ifm, ofm, expectedOutput, -1);
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200208
209 bool failed = inferenceProcess.runJob(job);
210
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200211 sendInferenceRsp(data.inferenceReq.user_arg, job.output, failed);
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200212 break;
213 }
214 default:
215 break;
216 }
217
218 return true;
219}
220
221void MessageProcess::sendPong() {
222 if (!queueOut.write(ETHOSU_CORE_MSG_PONG)) {
223 printf("Failed to write pong.\n");
224 }
225}
226
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200227void MessageProcess::sendInferenceRsp(uint64_t userArg, vector<DataPtr> &ofm, bool failed) {
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200228 ethosu_core_inference_rsp rsp;
229
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200230 rsp.user_arg = userArg;
231 rsp.ofm_count = ofm.size();
232 rsp.status = failed ? ETHOSU_CORE_STATUS_ERROR : ETHOSU_CORE_STATUS_OK;
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200233
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200234 for (size_t i = 0; i < ofm.size(); ++i) {
235 rsp.ofm_size[i] = ofm[i].size;
236 }
237
238 printf("Sending inference response. userArg=0x%llx, ofm_count=%u, status=%u\n",
239 rsp.user_arg,
240 rsp.ofm_count,
241 rsp.status);
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200242
243 if (!queueOut.write(ETHOSU_CORE_MSG_INFERENCE_RSP, rsp)) {
244 printf("Failed to write inference.\n");
245 }
246}
247} // namespace MessageProcess