Introduce ARCv2 architecture related code
[fw/openocd] / 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 }