blob: 931ebb133e6e230f27b87010dc611f43fea6cb54 [file] [log] [blame]
Kristofer Jonsson641c0912020-08-31 11:34:14 +02001/*
Anton Moberge348f8f2021-03-31 11:08:58 +02002 * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
Kristofer Jonsson641c0912020-08-31 11:34:14 +02003 *
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
Per Åstrandd9afc082020-10-06 13:25:08 +020021#include "cmsis_compiler.h"
22
Kristofer Jonsson641c0912020-08-31 11:34:14 +020023#include <cstddef>
24#include <cstdio>
Kristofer Jonsson25480142020-09-03 12:35:21 +020025#include <cstring>
Per Åstrand91a91732020-09-25 15:04:26 +020026#include <inttypes.h>
Kristofer Jonsson641c0912020-08-31 11:34:14 +020027
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +020028using namespace std;
29using namespace InferenceProcess;
Per Åstrand4edc1782021-01-12 14:33:36 +010030using namespace EthosU;
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +020031
Kristofer Jonsson641c0912020-08-31 11:34:14 +020032namespace MessageProcess {
33
Kristofer Jonsson68b4ad52020-12-10 15:11:27 +010034QueueImpl::QueueImpl(ethosu_core_queue &_queue) : queue(_queue) {
35 cleanHeaderData();
36}
Kristofer Jonsson641c0912020-08-31 11:34:14 +020037
38bool QueueImpl::empty() const {
Kristofer Jonsson2cda7fb2021-02-01 11:22:59 +010039 invalidateHeaderData();
40
Kristofer Jonsson641c0912020-08-31 11:34:14 +020041 return queue.header.read == queue.header.write;
42}
43
44size_t QueueImpl::available() const {
Kristofer Jonsson2cda7fb2021-02-01 11:22:59 +010045 invalidateHeaderData();
46
Kristofer Jonsson641c0912020-08-31 11:34:14 +020047 size_t avail = queue.header.write - queue.header.read;
48
49 if (queue.header.read > queue.header.write) {
50 avail += queue.header.size;
51 }
52
53 return avail;
54}
55
56size_t QueueImpl::capacity() const {
57 return queue.header.size - available();
58}
59
60bool QueueImpl::read(uint8_t *dst, uint32_t length) {
61 const uint8_t *end = dst + length;
Kristofer Jonsson641c0912020-08-31 11:34:14 +020062
Kristofer Jonsson2cda7fb2021-02-01 11:22:59 +010063 // Available will invalidate the cache
Kristofer Jonsson641c0912020-08-31 11:34:14 +020064 if (length > available()) {
65 return false;
66 }
67
Kristofer Jonsson2cda7fb2021-02-01 11:22:59 +010068 uint32_t rpos = queue.header.read;
69
Kristofer Jonsson641c0912020-08-31 11:34:14 +020070 while (dst < end) {
71 *dst++ = queue.data[rpos];
72 rpos = (rpos + 1) % queue.header.size;
73 }
74
75 queue.header.read = rpos;
76
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +010077 cleanHeader();
Kristofer Jonsson641c0912020-08-31 11:34:14 +020078
79 return true;
80}
81
82bool QueueImpl::write(const Vec *vec, size_t length) {
83 size_t total = 0;
84
85 for (size_t i = 0; i < length; i++) {
86 total += vec[i].length;
87 }
88
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +010089 invalidateHeader();
90
Kristofer Jonsson641c0912020-08-31 11:34:14 +020091 if (total > capacity()) {
92 return false;
93 }
94
95 uint32_t wpos = queue.header.write;
96
97 for (size_t i = 0; i < length; i++) {
98 const uint8_t *src = reinterpret_cast<const uint8_t *>(vec[i].base);
99 const uint8_t *end = src + vec[i].length;
100
101 while (src < end) {
102 queue.data[wpos] = *src++;
103 wpos = (wpos + 1) % queue.header.size;
104 }
105 }
106
107 // Update the write position last
108 queue.header.write = wpos;
109
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +0100110 cleanHeaderData();
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200111
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200112 return true;
113}
114
115bool QueueImpl::write(const uint32_t type, const void *src, uint32_t length) {
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100116 ethosu_core_msg msg = {ETHOSU_CORE_MSG_MAGIC, type, length};
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200117 Vec vec[2] = {{&msg, sizeof(msg)}, {src, length}};
118
119 return write(vec, 2);
120}
121
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100122// Skip to magic or end of queue
123void QueueImpl::reset() {
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +0100124 invalidateHeader();
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100125 queue.header.read = queue.header.write;
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +0100126 cleanHeader();
Per Åstranddc28b132020-09-28 13:02:18 +0200127}
128
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +0100129void QueueImpl::cleanHeader() const {
130#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
131 SCB_CleanDCache_by_Addr(reinterpret_cast<uint32_t *>(&queue.header), sizeof(queue.header));
132#endif
133}
134
135void QueueImpl::cleanHeaderData() const {
136#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
137 SCB_CleanDCache_by_Addr(reinterpret_cast<uint32_t *>(&queue.header), sizeof(queue.header));
Bhavik Patel97906eb2020-12-17 15:32:16 +0100138 uintptr_t queueDataPtr = reinterpret_cast<uintptr_t>(&queue.data[0]);
139 SCB_CleanDCache_by_Addr(reinterpret_cast<uint32_t *>(queueDataPtr & ~3), queue.header.size + (queueDataPtr & 3));
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +0100140#endif
141}
142
143void QueueImpl::invalidateHeader() const {
144#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
145 SCB_InvalidateDCache_by_Addr(reinterpret_cast<uint32_t *>(&queue.header), sizeof(queue.header));
146#endif
147}
148
149void QueueImpl::invalidateHeaderData() const {
150#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
151 SCB_InvalidateDCache_by_Addr(reinterpret_cast<uint32_t *>(&queue.header), sizeof(queue.header));
Bhavik Patel97906eb2020-12-17 15:32:16 +0100152 uintptr_t queueDataPtr = reinterpret_cast<uintptr_t>(&queue.data[0]);
153 SCB_InvalidateDCache_by_Addr(reinterpret_cast<uint32_t *>(queueDataPtr & ~3),
154 queue.header.size + (queueDataPtr & 3));
Kristofer Jonsson2cbaaa92020-11-19 16:14:46 +0100155#endif
156}
157
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200158MessageProcess::MessageProcess(ethosu_core_queue &in,
159 ethosu_core_queue &out,
Jonny Svärd44398c82020-10-06 14:18:28 +0200160 Mailbox::Mailbox &mbox,
Per Åstrandbbd9c8f2020-09-25 15:07:35 +0200161 ::InferenceProcess::InferenceProcess &_inferenceProcess) :
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200162 queueIn(in),
Jonny Svärd44398c82020-10-06 14:18:28 +0200163 queueOut(out), mailbox(mbox), inferenceProcess(_inferenceProcess) {
164 mailbox.registerCallback(mailboxCallback, reinterpret_cast<void *>(this));
165}
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200166
167void MessageProcess::run() {
168 while (true) {
169 // Handle all messages in queue
170 while (handleMessage())
171 ;
172
173 // Wait for event
174 __WFE();
175 }
176}
177
178void MessageProcess::handleIrq() {
179 __SEV();
180}
181
182bool MessageProcess::handleMessage() {
183 ethosu_core_msg msg;
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200184
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100185 if (queueIn.available() == 0) {
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200186 return false;
187 }
188
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100189 // Read msg header
190 // Only process a complete message header, else send error message
191 // and reset queue
192 if (!queueIn.read(msg)) {
193 sndErrorRspAndResetQueue(ETHOSU_CORE_MSG_ERR_INVALID_SIZE, "Failed to read a complete header");
194 return false;
195 }
196
197 printf("Msg: header magic=%" PRIX32 ", type=%" PRIu32 ", length=%" PRIu32 "\n", msg.magic, msg.type, msg.length);
198
199 if (msg.magic != ETHOSU_CORE_MSG_MAGIC) {
200 sndErrorRspAndResetQueue(ETHOSU_CORE_MSG_ERR_INVALID_MAGIC, "Invalid magic");
201 return false;
202 }
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200203
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200204 switch (msg.type) {
205 case ETHOSU_CORE_MSG_PING:
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100206 printf("Msg: Ping\n");
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200207 sendPong();
208 break;
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100209 case ETHOSU_CORE_MSG_ERR: {
210 struct ethosu_core_msg_err error = {0};
211 if (!queueIn.read(error)) {
212 printf("ERROR: Msg: Failed to receive error message\n");
213 } else {
214 printf("Msg: Received an error response, type=%" PRIu32 ", msg=\"%s\"\n", error.type, error.msg);
215 }
216 queueIn.reset();
217 return false;
218 }
219 case ETHOSU_CORE_MSG_VERSION_REQ:
220 printf("Msg: Version request\n");
221 sendVersionRsp();
222 break;
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200223 case ETHOSU_CORE_MSG_INFERENCE_REQ: {
Per Åstranddc28b132020-09-28 13:02:18 +0200224 ethosu_core_inference_req req;
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200225
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100226 if (!queueIn.read(req)) {
227 sndErrorRspAndResetQueue(ETHOSU_CORE_MSG_ERR_INVALID_PAYLOAD, "InferenceReq. Failed to read payload");
Per Åstranddc28b132020-09-28 13:02:18 +0200228 return false;
229 }
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200230
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100231 printf("Msg: InferenceReq. user_arg=0x%" PRIx64 ", network={0x%" PRIx32 ", %" PRIu32 "}",
Per Åstrand91a91732020-09-25 15:04:26 +0200232 req.user_arg,
233 req.network.ptr,
234 req.network.size);
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200235
Per Åstrand91a91732020-09-25 15:04:26 +0200236 printf(", ifm_count=%" PRIu32 ", ifm=[", req.ifm_count);
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200237 for (uint32_t i = 0; i < req.ifm_count; ++i) {
238 if (i > 0) {
239 printf(", ");
240 }
241
Per Åstrand91a91732020-09-25 15:04:26 +0200242 printf("{0x%" PRIx32 ", %" PRIu32 "}", req.ifm[i].ptr, req.ifm[i].size);
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200243 }
244 printf("]");
245
Per Åstrand91a91732020-09-25 15:04:26 +0200246 printf(", ofm_count=%" PRIu32 ", ofm=[", req.ofm_count);
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200247 for (uint32_t i = 0; i < req.ofm_count; ++i) {
248 if (i > 0) {
249 printf(", ");
250 }
251
Per Åstrand91a91732020-09-25 15:04:26 +0200252 printf("{0x%" PRIx32 ", %" PRIu32 "}", req.ofm[i].ptr, req.ofm[i].size);
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200253 }
254 printf("]\n");
255
256 DataPtr networkModel(reinterpret_cast<void *>(req.network.ptr), req.network.size);
257
258 vector<DataPtr> ifm;
259 for (uint32_t i = 0; i < req.ifm_count; ++i) {
260 ifm.push_back(DataPtr(reinterpret_cast<void *>(req.ifm[i].ptr), req.ifm[i].size));
261 }
262
263 vector<DataPtr> ofm;
264 for (uint32_t i = 0; i < req.ofm_count; ++i) {
265 ofm.push_back(DataPtr(reinterpret_cast<void *>(req.ofm[i].ptr), req.ofm[i].size));
266 }
267
268 vector<DataPtr> expectedOutput;
269
Jonny Svärde9f57dc2020-12-10 11:12:44 +0100270 vector<uint8_t> pmuEventConfig(ETHOSU_CORE_PMU_MAX);
Bhavik Patelffe845d2020-11-16 12:13:56 +0100271 for (uint32_t i = 0; i < ETHOSU_CORE_PMU_MAX; i++) {
272 pmuEventConfig[i] = req.pmu_event_config[i];
273 }
274
275 InferenceJob job(
276 "job", networkModel, ifm, ofm, expectedOutput, -1, pmuEventConfig, req.pmu_cycle_counter_enable);
Kristofer Jonsson34e24962020-11-23 16:22:10 +0100277 job.invalidate();
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200278
279 bool failed = inferenceProcess.runJob(job);
Kristofer Jonsson34e24962020-11-23 16:22:10 +0100280 job.clean();
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200281
Bhavik Patelffe845d2020-11-16 12:13:56 +0100282 sendInferenceRsp(req.user_arg,
283 job.output,
284 failed,
285 job.pmuEventConfig,
286 job.pmuCycleCounterEnable,
287 job.pmuEventCount,
288 job.pmuCycleCounterCount);
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200289 break;
290 }
Per Åstranddc28b132020-09-28 13:02:18 +0200291 default: {
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100292 char errMsg[128] = {0};
293 snprintf(&errMsg[0],
294 sizeof(errMsg),
295 "Msg: Unknown type: %" PRIu32 " with payload length %" PRIu32 " bytes\n",
296 msg.type,
297 msg.length);
298 sndErrorRspAndResetQueue(ETHOSU_CORE_MSG_ERR_UNSUPPORTED_TYPE, errMsg);
299 return false;
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200300 }
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100301 }
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200302 return true;
303}
304
305void MessageProcess::sendPong() {
306 if (!queueOut.write(ETHOSU_CORE_MSG_PONG)) {
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100307 printf("ERROR: Msg: Failed to write pong response. No mailbox message sent\n");
308 } else {
309 mailbox.sendMessage();
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200310 }
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100311}
312
313void MessageProcess::sendVersionRsp() {
314 struct ethosu_core_msg_version ver = {.major = ETHOSU_CORE_MSG_VERSION_MAJOR,
315 .minor = ETHOSU_CORE_MSG_VERSION_MINOR,
316 .patch = ETHOSU_CORE_MSG_VERSION_PATCH,
317 ._reserved = 0};
318
319 if (!queueOut.write(ETHOSU_CORE_MSG_VERSION_RSP, ver)) {
320 printf("ERROR: Failed to write version response. No mailbox message sent\n");
321 } else {
322 mailbox.sendMessage();
323 }
324}
325
326void MessageProcess::sndErrorRspAndResetQueue(ethosu_core_msg_err_type type, const char *message) {
327 ethosu_core_msg_err error = {0};
328 error.type = type;
329 unsigned int i = 0;
330
331 if (message) {
332 for (; i < (sizeof(error.msg) - 1) && message[i]; i++) {
333 error.msg[i] = message[i];
334 }
335 }
336 printf("ERROR: Msg: \"%s\"\n", message);
337 if (!queueOut.write(ETHOSU_CORE_MSG_ERR, &error)) {
338 printf("ERROR: Msg: Failed to write error response. No mailbox message sent\n");
339 return;
340 }
341 queueIn.reset();
Jonny Svärd44398c82020-10-06 14:18:28 +0200342 mailbox.sendMessage();
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200343}
344
Bhavik Patelffe845d2020-11-16 12:13:56 +0100345void MessageProcess::sendInferenceRsp(uint64_t userArg,
346 vector<DataPtr> &ofm,
347 bool failed,
348 vector<uint8_t> &pmuEventConfig,
349 uint32_t pmuCycleCounterEnable,
350 vector<uint32_t> &pmuEventCount,
351 uint64_t pmuCycleCounterCount) {
352 ethosu_core_inference_rsp rsp = {
353 .pmu_event_count =
354 {
355 0,
356 },
357 };
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200358
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200359 rsp.user_arg = userArg;
360 rsp.ofm_count = ofm.size();
361 rsp.status = failed ? ETHOSU_CORE_STATUS_ERROR : ETHOSU_CORE_STATUS_OK;
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200362
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200363 for (size_t i = 0; i < ofm.size(); ++i) {
364 rsp.ofm_size[i] = ofm[i].size;
365 }
366
Bhavik Patelffe845d2020-11-16 12:13:56 +0100367 for (size_t i = 0; i < pmuEventConfig.size(); i++) {
368 rsp.pmu_event_config[i] = pmuEventConfig[i];
369 }
370 rsp.pmu_cycle_counter_enable = pmuCycleCounterEnable;
371 for (size_t i = 0; i < pmuEventCount.size(); i++) {
372 rsp.pmu_event_count[i] = pmuEventCount[i];
373 }
374 rsp.pmu_cycle_counter_count = pmuCycleCounterCount;
375
Per Åstrand91a91732020-09-25 15:04:26 +0200376 printf("Sending inference response. userArg=0x%" PRIx64 ", ofm_count=%" PRIu32 ", status=%" PRIu32 "\n",
Kristofer Jonsson72fa50b2020-09-10 13:26:41 +0200377 rsp.user_arg,
378 rsp.ofm_count,
379 rsp.status);
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200380
381 if (!queueOut.write(ETHOSU_CORE_MSG_INFERENCE_RSP, rsp)) {
Jonny Svärddc84f4f2021-01-14 19:54:54 +0100382 printf("ERROR: Msg: Failed to write inference response. No mailbox message sent\n");
383 } else {
384 mailbox.sendMessage();
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200385 }
386}
Jonny Svärd44398c82020-10-06 14:18:28 +0200387
388void MessageProcess::mailboxCallback(void *userArg) {
389 MessageProcess *_this = reinterpret_cast<MessageProcess *>(userArg);
390 _this->handleIrq();
391}
392
Kristofer Jonsson641c0912020-08-31 11:34:14 +0200393} // namespace MessageProcess