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

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)