jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / target / arc_mem.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. *
5 * Frank Dols <frank.dols@synopsys.com> *
6 * Mischa Jonker <mischa.jonker@synopsys.com> *
7 * Anton Kolesov <anton.kolesov@synopsys.com> *
8 * Evgeniy Didin <didin@synopsys.com> *
9 ***************************************************************************/
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #include "arc.h"
16
17 /* ----- Supporting functions ---------------------------------------------- */
18 static bool arc_mem_is_slow_memory(struct arc_common *arc, uint32_t addr,
19 uint32_t size, uint32_t count)
20 {
21 uint32_t addr_end = addr + size * count;
22 /* `_end` field can overflow - it points to the first byte after the end,
23 * therefore if DCCM is right at the end of memory address space, then
24 * dccm_end will be 0. */
25 assert(addr_end >= addr || addr_end == 0);
26
27 return !((addr >= arc->dccm_start && addr_end <= arc->dccm_end) ||
28 (addr >= arc->iccm0_start && addr_end <= arc->iccm0_end) ||
29 (addr >= arc->iccm1_start && addr_end <= arc->iccm1_end));
30 }
31
32 /* Write word at word-aligned address */
33 static int arc_mem_write_block32(struct target *target, uint32_t addr,
34 uint32_t count, void *buf)
35 {
36 struct arc_common *arc = target_to_arc(target);
37
38 LOG_DEBUG("Write 4-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
39 addr, count);
40
41 /* Check arguments */
42 assert(!(addr & 3));
43
44 /* We need to flush the cache since it might contain dirty
45 * lines, so the cache invalidation may cause data inconsistency. */
46 CHECK_RETVAL(arc_cache_flush(target));
47
48
49 /* No need to flush cache, because we don't read values from memory. */
50 CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, addr, count,
51 (uint32_t *)buf));
52
53 /* Invalidate caches. */
54 CHECK_RETVAL(arc_cache_invalidate(target));
55
56 return ERROR_OK;
57 }
58
59 /* Write half-word at half-word-aligned address */
60 static int arc_mem_write_block16(struct target *target, uint32_t addr,
61 uint32_t count, void *buf)
62 {
63 struct arc_common *arc = target_to_arc(target);
64 uint32_t i;
65 uint32_t buffer_he;
66 uint8_t buffer_te[sizeof(uint32_t)];
67 uint8_t halfword_te[sizeof(uint16_t)];
68
69 LOG_DEBUG("Write 2-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
70 addr, count);
71
72 /* Check arguments */
73 assert(!(addr & 1));
74
75 /* We will read data from memory, so we need to flush the cache. */
76 CHECK_RETVAL(arc_cache_flush(target));
77
78 /* non-word writes are less common than 4-byte writes, so I suppose we can
79 * allow ourselves to write this in a cycle, instead of calling arc_jtag
80 * with count > 1. */
81 for (i = 0; i < count; i++) {
82 /* We can read only word at word-aligned address. Also *jtag_read_memory
83 * functions return data in host endianness, so host endianness !=
84 * target endianness we have to convert data back to target endianness,
85 * or bytes will be at the wrong places.So:
86 * 1) read word
87 * 2) convert to target endianness
88 * 3) make changes
89 * 4) convert back to host endianness
90 * 5) write word back to target.
91 */
92 bool is_slow_memory = arc_mem_is_slow_memory(arc,
93 (addr + i * sizeof(uint16_t)) & ~3u, 4, 1);
94 CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info,
95 (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he,
96 is_slow_memory));
97 target_buffer_set_u32(target, buffer_te, buffer_he);
98
99 /* buf is in host endianness, convert to target */
100 target_buffer_set_u16(target, halfword_te, ((uint16_t *)buf)[i]);
101
102 memcpy(buffer_te + ((addr + i * sizeof(uint16_t)) & 3u),
103 halfword_te, sizeof(uint16_t));
104
105 buffer_he = target_buffer_get_u32(target, buffer_te);
106
107 CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info,
108 (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he));
109 }
110
111 /* Invalidate caches. */
112 CHECK_RETVAL(arc_cache_invalidate(target));
113
114 return ERROR_OK;
115 }
116
117 /* Write byte at address */
118 static int arc_mem_write_block8(struct target *target, uint32_t addr,
119 uint32_t count, void *buf)
120 {
121 struct arc_common *arc = target_to_arc(target);
122 uint32_t i;
123 uint32_t buffer_he;
124 uint8_t buffer_te[sizeof(uint32_t)];
125
126
127 LOG_DEBUG("Write 1-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
128 addr, count);
129
130 /* We will read data from memory, so we need to flush the cache. */
131 CHECK_RETVAL(arc_cache_flush(target));
132
133 /* non-word writes are less common than 4-byte writes, so I suppose we can
134 * allow ourselves to write this in a cycle, instead of calling arc_jtag
135 * with count > 1. */
136 for (i = 0; i < count; i++) {
137 /* See comment in arc_mem_write_block16 for details. Since it is a byte
138 * there is not need to convert write buffer to target endianness, but
139 * we still have to convert read buffer. */
140 CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he,
141 arc_mem_is_slow_memory(arc, (addr + i) & ~3, 4, 1)));
142 target_buffer_set_u32(target, buffer_te, buffer_he);
143 memcpy(buffer_te + ((addr + i) & 3), (uint8_t *)buf + i, 1);
144 buffer_he = target_buffer_get_u32(target, buffer_te);
145 CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he));
146 }
147
148 /* Invalidate caches. */
149 CHECK_RETVAL(arc_cache_invalidate(target));
150
151 return ERROR_OK;
152 }
153
154 /* ----- Exported functions ------------------------------------------------ */
155 int arc_mem_write(struct target *target, target_addr_t address, uint32_t size,
156 uint32_t count, const uint8_t *buffer)
157 {
158 int retval = ERROR_OK;
159 void *tunnel = NULL;
160
161 LOG_DEBUG("address: 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: %" PRIu32,
162 address, size, count);
163
164 if (target->state != TARGET_HALTED) {
165 LOG_WARNING("target not halted");
166 return ERROR_TARGET_NOT_HALTED;
167 }
168
169 /* sanitize arguments */
170 if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer))
171 return ERROR_COMMAND_SYNTAX_ERROR;
172
173 if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
174 return ERROR_TARGET_UNALIGNED_ACCESS;
175
176 /* correct endianness if we have word or hword access */
177 if (size > 1) {
178 /*
179 * arc_..._write_mem with size 4/2 requires uint32_t/uint16_t
180 * in host endianness, but byte array represents target endianness.
181 */
182 tunnel = calloc(1, count * size * sizeof(uint8_t));
183
184 if (!tunnel) {
185 LOG_ERROR("Unable to allocate memory");
186 return ERROR_FAIL;
187 }
188
189 switch (size) {
190 case 4:
191 target_buffer_get_u32_array(target, buffer, count,
192 (uint32_t *)tunnel);
193 break;
194 case 2:
195 target_buffer_get_u16_array(target, buffer, count,
196 (uint16_t *)tunnel);
197 break;
198 }
199 buffer = tunnel;
200 }
201
202 if (size == 4) {
203 retval = arc_mem_write_block32(target, address, count, (void *)buffer);
204 } else if (size == 2) {
205 /* We convert buffer from host endianness to target. But then in
206 * write_block16, we do the reverse. Is there a way to avoid this without
207 * breaking other cases? */
208 retval = arc_mem_write_block16(target, address, count, (void *)buffer);
209 } else {
210 retval = arc_mem_write_block8(target, address, count, (void *)buffer);
211 }
212
213 free(tunnel);
214
215 return retval;
216 }
217
218 static int arc_mem_read_block(struct target *target, target_addr_t addr,
219 uint32_t size, uint32_t count, void *buf)
220 {
221 struct arc_common *arc = target_to_arc(target);
222
223 LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32
224 ", count=%" PRIu32, addr, size, count);
225 assert(!(addr & 3));
226 assert(size == 4);
227
228 /* Flush cache before memory access */
229 CHECK_RETVAL(arc_cache_flush(target));
230
231 CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, addr, count, buf,
232 arc_mem_is_slow_memory(arc, addr, size, count)));
233
234 return ERROR_OK;
235 }
236
237 int arc_mem_read(struct target *target, target_addr_t address, uint32_t size,
238 uint32_t count, uint8_t *buffer)
239 {
240 int retval = ERROR_OK;
241 void *tunnel_he;
242 uint8_t *tunnel_te;
243 uint32_t words_to_read, bytes_to_read;
244
245
246 LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32
247 ", count=%" PRIu32, address, size, count);
248
249 if (target->state != TARGET_HALTED) {
250 LOG_WARNING("target not halted");
251 return ERROR_TARGET_NOT_HALTED;
252 }
253
254 /* Sanitize arguments */
255 if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer))
256 return ERROR_COMMAND_SYNTAX_ERROR;
257
258 if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
259 return ERROR_TARGET_UNALIGNED_ACCESS;
260
261 /* Reads are word-aligned, so padding might be required if count > 1.
262 * NB: +3 is a padding for the last word (in case it's not aligned;
263 * addr&3 is a padding for the first word (since address can be
264 * unaligned as well). */
265 bytes_to_read = (count * size + 3 + (address & 3u)) & ~3u;
266 words_to_read = bytes_to_read >> 2;
267 tunnel_he = calloc(1, bytes_to_read);
268 tunnel_te = calloc(1, bytes_to_read);
269
270 if (!tunnel_he || !tunnel_te) {
271 LOG_ERROR("Unable to allocate memory");
272 free(tunnel_he);
273 free(tunnel_te);
274 return ERROR_FAIL;
275 }
276
277 /* We can read only word-aligned words. */
278 retval = arc_mem_read_block(target, address & ~3u, sizeof(uint32_t),
279 words_to_read, tunnel_he);
280
281 /* arc_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */
282 /* endianness, but byte array should represent target endianness */
283
284 if (retval == ERROR_OK) {
285 switch (size) {
286 case 4:
287 target_buffer_set_u32_array(target, buffer, count,
288 tunnel_he);
289 break;
290 case 2:
291 target_buffer_set_u32_array(target, tunnel_te,
292 words_to_read, tunnel_he);
293 /* Will that work properly with count > 1 and big endian? */
294 memcpy(buffer, tunnel_te + (address & 3u),
295 count * sizeof(uint16_t));
296 break;
297 case 1:
298 target_buffer_set_u32_array(target, tunnel_te,
299 words_to_read, tunnel_he);
300 /* Will that work properly with count > 1 and big endian? */
301 memcpy(buffer, tunnel_te + (address & 3u), count);
302 break;
303 }
304 }
305
306 free(tunnel_he);
307 free(tunnel_te);
308
309 return retval;
310 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)