blob: 4001f8c0cc6d3446576ff7cad80e3b969bd834a3 [file] [log] [blame]
Yulia Garbovichf61ea352021-11-11 14:16:57 +02001/*
Kristofer Jonssonac535f02022-03-10 11:08:39 +01002 * Copyright (c) 2020-2022 Arm Limited.
Yulia Garbovichf61ea352021-11-11 14:16:57 +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_queue.hpp"
20
21#include <cstddef>
22#include <cstdio>
23#include <cstring>
24#include <inttypes.h>
25
26namespace MessageQueue {
27
28QueueImpl::QueueImpl(EthosU::ethosu_core_queue &_queue) : queue(_queue) {
29 cleanHeaderData();
30}
31
32bool QueueImpl::empty() const {
33 invalidateHeaderData();
34
35 return queue.header.read == queue.header.write;
36}
37
38size_t QueueImpl::available() const {
39 invalidateHeaderData();
40
41 size_t avail = queue.header.write - queue.header.read;
42
43 if (queue.header.read > queue.header.write) {
44 avail += queue.header.size;
45 }
46
47 return avail;
48}
49
50size_t QueueImpl::capacity() const {
Kristofer Jonsson1142d9c2022-06-28 14:16:04 +020051 return queue.header.size - available() - 1;
Yulia Garbovichf61ea352021-11-11 14:16:57 +020052}
53
54bool QueueImpl::read(uint8_t *dst, uint32_t length) {
55 const uint8_t *end = dst + length;
56
57 // Available will invalidate the cache
58 if (length > available()) {
59 return false;
60 }
61
62 uint32_t rpos = queue.header.read;
63
64 while (dst < end) {
65 *dst++ = queue.data[rpos];
66 rpos = (rpos + 1) % queue.header.size;
67 }
68
69 queue.header.read = rpos;
70
71 cleanHeader();
72
73 return true;
74}
75
76bool QueueImpl::write(const Vec *vec, size_t length) {
77 size_t total = 0;
78
79 for (size_t i = 0; i < length; i++) {
80 total += vec[i].length;
81 }
82
83 invalidateHeader();
84
85 if (total > capacity()) {
86 return false;
87 }
88
89 uint32_t wpos = queue.header.write;
90
91 for (size_t i = 0; i < length; i++) {
92 const uint8_t *src = reinterpret_cast<const uint8_t *>(vec[i].base);
93 const uint8_t *end = src + vec[i].length;
94
95 while (src < end) {
96 queue.data[wpos] = *src++;
97 wpos = (wpos + 1) % queue.header.size;
98 }
99 }
100
101 // Update the write position last
102 queue.header.write = wpos;
103
104 cleanHeaderData();
105
106 return true;
107}
108
109bool QueueImpl::write(const uint32_t type, const void *src, uint32_t length) {
110 EthosU::ethosu_core_msg msg = {ETHOSU_CORE_MSG_MAGIC, type, length};
111 Vec vec[2] = {{&msg, sizeof(msg)}, {src, length}};
112
113 return write(vec, 2);
114}
115
116// Skip to magic or end of queue
117void QueueImpl::reset() {
118 invalidateHeader();
119 queue.header.read = queue.header.write;
120 cleanHeader();
121}
122
123void QueueImpl::cleanHeader() const {
124#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
125 SCB_CleanDCache_by_Addr(reinterpret_cast<uint32_t *>(&queue.header), sizeof(queue.header));
126#endif
127}
128
129void QueueImpl::cleanHeaderData() const {
130#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
131 SCB_CleanDCache_by_Addr(reinterpret_cast<uint32_t *>(&queue.header), sizeof(queue.header));
132 uintptr_t queueDataPtr = reinterpret_cast<uintptr_t>(&queue.data[0]);
133 SCB_CleanDCache_by_Addr(reinterpret_cast<uint32_t *>(queueDataPtr & ~3), queue.header.size + (queueDataPtr & 3));
134#endif
135}
136
137void QueueImpl::invalidateHeader() const {
138#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
139 SCB_InvalidateDCache_by_Addr(reinterpret_cast<uint32_t *>(&queue.header), sizeof(queue.header));
140#endif
141}
142
143void QueueImpl::invalidateHeaderData() const {
144#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
145 SCB_InvalidateDCache_by_Addr(reinterpret_cast<uint32_t *>(&queue.header), sizeof(queue.header));
146 uintptr_t queueDataPtr = reinterpret_cast<uintptr_t>(&queue.data[0]);
147 SCB_InvalidateDCache_by_Addr(reinterpret_cast<uint32_t *>(queueDataPtr & ~3),
148 queue.header.size + (queueDataPtr & 3));
149#endif
150}
151} // namespace MessageQueue