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> *
8 * SPDX-License-Identifier: GPL-2.0-or-later *
9 ***************************************************************************/
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
)
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);
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
));
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
)
36 struct arc_common
*arc
= target_to_arc(target
);
38 LOG_DEBUG("Write 4-byte memory block: addr=0x%08" PRIx32
", count=%" PRIu32
,
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
));
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
,
53 /* Invalidate caches. */
54 CHECK_RETVAL(arc_cache_invalidate(target
));
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
)
63 struct arc_common
*arc
= target_to_arc(target
);
66 uint8_t buffer_te
[sizeof(uint32_t)];
67 uint8_t halfword_te
[sizeof(uint16_t)];
69 LOG_DEBUG("Write 2-byte memory block: addr=0x%08" PRIx32
", count=%" PRIu32
,
75 /* We will read data from memory, so we need to flush the cache. */
76 CHECK_RETVAL(arc_cache_flush(target
));
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
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:
87 * 2) convert to target endianness
89 * 4) convert back to host endianness
90 * 5) write word back to target.
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
,
97 target_buffer_set_u32(target
, buffer_te
, buffer_he
);
99 /* buf is in host endianness, convert to target */
100 target_buffer_set_u16(target
, halfword_te
, ((uint16_t *)buf
)[i
]);
102 memcpy(buffer_te
+ ((addr
+ i
* sizeof(uint16_t)) & 3u),
103 halfword_te
, sizeof(uint16_t));
105 buffer_he
= target_buffer_get_u32(target
, buffer_te
);
107 CHECK_RETVAL(arc_jtag_write_memory(&arc
->jtag_info
,
108 (addr
+ i
* sizeof(uint16_t)) & ~3u, 1, &buffer_he
));
111 /* Invalidate caches. */
112 CHECK_RETVAL(arc_cache_invalidate(target
));
117 /* Write byte at address */
118 static int arc_mem_write_block8(struct target
*target
, uint32_t addr
,
119 uint32_t count
, void *buf
)
121 struct arc_common
*arc
= target_to_arc(target
);
124 uint8_t buffer_te
[sizeof(uint32_t)];
127 LOG_DEBUG("Write 1-byte memory block: addr=0x%08" PRIx32
", count=%" PRIu32
,
130 /* We will read data from memory, so we need to flush the cache. */
131 CHECK_RETVAL(arc_cache_flush(target
));
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
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
));
148 /* Invalidate caches. */
149 CHECK_RETVAL(arc_cache_invalidate(target
));
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
)
158 int retval
= ERROR_OK
;
161 LOG_DEBUG("address: 0x%08" TARGET_PRIxADDR
", size: %" PRIu32
", count: %" PRIu32
,
162 address
, size
, count
);
164 if (target
->state
!= TARGET_HALTED
) {
165 LOG_WARNING("target not halted");
166 return ERROR_TARGET_NOT_HALTED
;
169 /* sanitize arguments */
170 if (((size
!= 4) && (size
!= 2) && (size
!= 1)) || !(count
) || !(buffer
))
171 return ERROR_COMMAND_SYNTAX_ERROR
;
173 if (((size
== 4) && (address
& 0x3u
)) || ((size
== 2) && (address
& 0x1u
)))
174 return ERROR_TARGET_UNALIGNED_ACCESS
;
176 /* correct endianness if we have word or hword access */
179 * arc_..._write_mem with size 4/2 requires uint32_t/uint16_t
180 * in host endianness, but byte array represents target endianness.
182 tunnel
= calloc(1, count
* size
* sizeof(uint8_t));
185 LOG_ERROR("Unable to allocate memory");
191 target_buffer_get_u32_array(target
, buffer
, count
,
195 target_buffer_get_u16_array(target
, buffer
, count
,
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
);
210 retval
= arc_mem_write_block8(target
, address
, count
, (void *)buffer
);
218 static int arc_mem_read_block(struct target
*target
, target_addr_t addr
,
219 uint32_t size
, uint32_t count
, void *buf
)
221 struct arc_common
*arc
= target_to_arc(target
);
223 LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR
", size=%" PRIu32
224 ", count=%" PRIu32
, addr
, size
, count
);
228 /* Flush cache before memory access */
229 CHECK_RETVAL(arc_cache_flush(target
));
231 CHECK_RETVAL(arc_jtag_read_memory(&arc
->jtag_info
, addr
, count
, buf
,
232 arc_mem_is_slow_memory(arc
, addr
, size
, count
)));
237 int arc_mem_read(struct target
*target
, target_addr_t address
, uint32_t size
,
238 uint32_t count
, uint8_t *buffer
)
240 int retval
= ERROR_OK
;
243 uint32_t words_to_read
, bytes_to_read
;
246 LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR
", size=%" PRIu32
247 ", count=%" PRIu32
, address
, size
, count
);
249 if (target
->state
!= TARGET_HALTED
) {
250 LOG_WARNING("target not halted");
251 return ERROR_TARGET_NOT_HALTED
;
254 /* Sanitize arguments */
255 if (((size
!= 4) && (size
!= 2) && (size
!= 1)) || !(count
) || !(buffer
))
256 return ERROR_COMMAND_SYNTAX_ERROR
;
258 if (((size
== 4) && (address
& 0x3u
)) || ((size
== 2) && (address
& 0x1u
)))
259 return ERROR_TARGET_UNALIGNED_ACCESS
;
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
);
270 if (!tunnel_he
|| !tunnel_te
) {
271 LOG_ERROR("Unable to allocate memory");
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
);
281 /* arc_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */
282 /* endianness, but byte array should represent target endianness */
284 if (ERROR_OK
== retval
) {
287 target_buffer_set_u32_array(target
, buffer
, count
,
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));
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
);
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)