quark_x10xx: add new target quark_x10xx
[openocd.git] / src / target / nds32_v3m.c
1 /***************************************************************************
2 * Copyright (C) 2013 Andes Technology *
3 * Hsiangkai Wang <hkwang@andestech.com> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "breakpoints.h"
26 #include "nds32_cmd.h"
27 #include "nds32_aice.h"
28 #include "nds32_v3m.h"
29 #include "nds32_v3_common.h"
30
31 static int nds32_v3m_activate_hardware_breakpoint(struct target *target)
32 {
33 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
34 struct aice_port_s *aice = target_to_aice(target);
35 struct breakpoint *bp;
36 unsigned brp_num = nds32_v3m->n_hbr - 1;
37
38 for (bp = target->breakpoints; bp; bp = bp->next) {
39 if (bp->type == BKPT_SOFT) {
40 /* already set at nds32_v3m_add_breakpoint() */
41 continue;
42 } else if (bp->type == BKPT_HARD) {
43 /* set address */
44 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + brp_num, bp->address);
45 /* set mask */
46 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + brp_num, 0);
47
48 if (nds32_v3m->nds32.memory.address_translation)
49 /* enable breakpoint (virtual address) */
50 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x2);
51 else
52 /* enable breakpoint (physical address) */
53 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0xA);
54
55 LOG_DEBUG("Add hardware BP %u at %08" PRIx32, brp_num,
56 bp->address);
57
58 brp_num--;
59 } else {
60 return ERROR_FAIL;
61 }
62 }
63
64 return ERROR_OK;
65 }
66
67 static int nds32_v3m_deactivate_hardware_breakpoint(struct target *target)
68 {
69 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
70 struct aice_port_s *aice = target_to_aice(target);
71 struct breakpoint *bp;
72 unsigned brp_num = nds32_v3m->n_hbr - 1;
73
74 for (bp = target->breakpoints; bp; bp = bp->next) {
75 if (bp->type == BKPT_SOFT)
76 continue;
77 else if (bp->type == BKPT_HARD)
78 /* disable breakpoint */
79 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x0);
80 else
81 return ERROR_FAIL;
82
83 LOG_DEBUG("Remove hardware BP %u at %08" PRIx32, brp_num,
84 bp->address);
85
86 brp_num--;
87 }
88
89 return ERROR_OK;
90 }
91
92 static int nds32_v3m_activate_hardware_watchpoint(struct target *target)
93 {
94 struct aice_port_s *aice = target_to_aice(target);
95 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
96 struct watchpoint *wp;
97 int32_t wp_num = 0;
98 uint32_t wp_config = 0;
99 bool ld_stop, st_stop;
100
101 if (nds32_v3m->nds32.global_stop)
102 ld_stop = st_stop = false;
103
104 for (wp = target->watchpoints; wp; wp = wp->next) {
105
106 if (wp_num < nds32_v3m->used_n_wp) {
107 wp->mask = wp->length - 1;
108 if ((wp->address % wp->length) != 0)
109 wp->mask = (wp->mask << 1) + 1;
110
111 if (wp->rw == WPT_READ)
112 wp_config = 0x3;
113 else if (wp->rw == WPT_WRITE)
114 wp_config = 0x5;
115 else if (wp->rw == WPT_ACCESS)
116 wp_config = 0x7;
117
118 /* set/unset physical address bit of BPCn according to PSW.DT */
119 if (nds32_v3m->nds32.memory.address_translation == false)
120 wp_config |= 0x8;
121
122 /* set address */
123 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
124 wp->address - (wp->address % wp->length));
125 /* set mask */
126 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
127 /* enable watchpoint */
128 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
129
130 LOG_DEBUG("Add hardware wathcpoint %" PRId32 " at %08" PRIx32
131 " mask %08" PRIx32, wp_num, wp->address, wp->mask);
132
133 wp_num++;
134 } else if (nds32_v3m->nds32.global_stop) {
135 if (wp->rw == WPT_READ)
136 ld_stop = true;
137 else if (wp->rw == WPT_WRITE)
138 st_stop = true;
139 else if (wp->rw == WPT_ACCESS)
140 ld_stop = st_stop = true;
141 }
142 }
143
144 if (nds32_v3m->nds32.global_stop) {
145 uint32_t edm_ctl;
146 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
147 if (ld_stop)
148 edm_ctl |= 0x10;
149 if (st_stop)
150 edm_ctl |= 0x20;
151 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
152 }
153
154 return ERROR_OK;
155 }
156
157 static int nds32_v3m_deactivate_hardware_watchpoint(struct target *target)
158 {
159 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
160 struct aice_port_s *aice = target_to_aice(target);
161 struct watchpoint *wp;
162 int32_t wp_num = 0;
163 bool clean_global_stop = false;
164
165 for (wp = target->watchpoints; wp; wp = wp->next) {
166
167 if (wp_num < nds32_v3m->used_n_wp) {
168 /* disable watchpoint */
169 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
170
171 LOG_DEBUG("Remove hardware wathcpoint %" PRId32 " at %08" PRIx32
172 " mask %08" PRIx32, wp_num, wp->address, wp->mask);
173 wp_num++;
174 } else if (nds32_v3m->nds32.global_stop) {
175 clean_global_stop = true;
176 }
177 }
178
179 if (clean_global_stop) {
180 uint32_t edm_ctl;
181 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
182 edm_ctl = edm_ctl & (~0x30);
183 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
184 }
185
186 return ERROR_OK;
187 }
188
189 static int nds32_v3m_check_interrupt_stack(struct nds32 *nds32)
190 {
191 uint32_t val_ir0;
192 uint32_t value;
193
194 /* Save interrupt level */
195 nds32_get_mapped_reg(nds32, IR0, &val_ir0);
196 nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
197
198 if (nds32_reach_max_interrupt_level(nds32))
199 LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->",
200 nds32->current_interrupt_level);
201
202 /* backup $ir6 to avoid suppressed exception overwrite */
203 nds32_get_mapped_reg(nds32, IR6, &value);
204
205 return ERROR_OK;
206 }
207
208 static int nds32_v3m_restore_interrupt_stack(struct nds32 *nds32)
209 {
210 uint32_t value;
211
212 /* get backup value from cache */
213 /* then set back to make the register dirty */
214 nds32_get_mapped_reg(nds32, IR0, &value);
215 nds32_set_mapped_reg(nds32, IR0, value);
216
217 nds32_get_mapped_reg(nds32, IR6, &value);
218 nds32_set_mapped_reg(nds32, IR6, value);
219
220 return ERROR_OK;
221 }
222
223 static int nds32_v3m_deassert_reset(struct target *target)
224 {
225 int retval;
226
227 CHECK_RETVAL(nds32_poll(target));
228
229 if (target->state != TARGET_HALTED) {
230 /* reset only */
231 LOG_WARNING("%s: ran after reset and before halt ...",
232 target_name(target));
233 retval = target_halt(target);
234 if (retval != ERROR_OK)
235 return retval;
236
237 }
238
239 return ERROR_OK;
240 }
241
242 static int nds32_v3m_add_breakpoint(struct target *target,
243 struct breakpoint *breakpoint)
244 {
245 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
246 struct nds32 *nds32 = &(nds32_v3m->nds32);
247 int result;
248
249 if (breakpoint->type == BKPT_HARD) {
250 /* check hardware resource */
251 if (nds32_v3m->next_hbr_index < nds32_v3m->next_hwp_index) {
252 LOG_WARNING("<-- TARGET WARNING! Insert too many "
253 "hardware breakpoints/watchpoints! "
254 "The limit of combined hardware "
255 "breakpoints/watchpoints is %" PRId32 ". -->",
256 nds32_v3m->n_hbr);
257 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
258 "hardware breakpoint: %" PRId32 ", hardware "
259 "watchpoints: %" PRId32 ". -->",
260 nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
261 nds32_v3m->used_n_wp);
262 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
263 }
264
265 /* update next place to put hardware breakpoint */
266 nds32_v3m->next_hbr_index--;
267
268 /* hardware breakpoint insertion occurs before 'continue' actually */
269 return ERROR_OK;
270 } else if (breakpoint->type == BKPT_SOFT) {
271 result = nds32_add_software_breakpoint(target, breakpoint);
272 if (ERROR_OK != result) {
273 /* auto convert to hardware breakpoint if failed */
274 if (nds32->auto_convert_hw_bp) {
275 /* convert to hardware breakpoint */
276 breakpoint->type = BKPT_HARD;
277
278 return nds32_v3m_add_breakpoint(target, breakpoint);
279 }
280 }
281
282 return result;
283 } else /* unrecognized breakpoint type */
284 return ERROR_FAIL;
285
286 return ERROR_OK;
287 }
288
289 static int nds32_v3m_remove_breakpoint(struct target *target,
290 struct breakpoint *breakpoint)
291 {
292 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
293
294 if (breakpoint->type == BKPT_HARD) {
295 if (nds32_v3m->next_hbr_index >= nds32_v3m->n_hbr - 1)
296 return ERROR_FAIL;
297
298 /* update next place to put hardware breakpoint */
299 nds32_v3m->next_hbr_index++;
300
301 /* hardware breakpoint removal occurs after 'halted' actually */
302 return ERROR_OK;
303 } else if (breakpoint->type == BKPT_SOFT) {
304 return nds32_remove_software_breakpoint(target, breakpoint);
305 } else /* unrecognized breakpoint type */
306 return ERROR_FAIL;
307
308 return ERROR_OK;
309 }
310
311 static int nds32_v3m_add_watchpoint(struct target *target,
312 struct watchpoint *watchpoint)
313 {
314 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
315
316 /* check hardware resource */
317 if (nds32_v3m->next_hwp_index >= nds32_v3m->n_hwp) {
318 /* No hardware resource */
319 if (nds32_v3m->nds32.global_stop) {
320 LOG_WARNING("<-- TARGET WARNING! The number of "
321 "watchpoints exceeds the hardware "
322 "resources. Stop at every load/store "
323 "instruction to check for watchpoint matches. -->");
324 return ERROR_OK;
325 }
326
327 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
328 "watchpoints! The limit of hardware watchpoints "
329 "is %" PRId32 ". -->", nds32_v3m->n_hwp);
330 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
331 "hardware watchpoint: %" PRId32 ". -->",
332 nds32_v3m->used_n_wp);
333 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
334 }
335
336 if (nds32_v3m->next_hwp_index > nds32_v3m->next_hbr_index) {
337 /* No hardware resource */
338 if (nds32_v3m->nds32.global_stop) {
339 LOG_WARNING("<-- TARGET WARNING! The number of "
340 "watchpoints exceeds the hardware "
341 "resources. Stop at every load/store "
342 "instruction to check for watchpoint matches. -->");
343 return ERROR_OK;
344 }
345
346 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
347 "breakpoints/watchpoints! The limit of combined "
348 "hardware breakpoints/watchpoints is %" PRId32 ". -->",
349 nds32_v3m->n_hbr);
350 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
351 "hardware breakpoint: %" PRId32 ", hardware "
352 "watchpoints: %" PRId32 ". -->",
353 nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
354 nds32_v3m->used_n_wp);
355 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
356 }
357
358 /* update next place to put hardware watchpoint */
359 nds32_v3m->next_hwp_index++;
360 nds32_v3m->used_n_wp++;
361
362 return ERROR_OK;
363 }
364
365 static int nds32_v3m_remove_watchpoint(struct target *target,
366 struct watchpoint *watchpoint)
367 {
368 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
369
370 if (nds32_v3m->next_hwp_index <= 0) {
371 if (nds32_v3m->nds32.global_stop)
372 return ERROR_OK;
373
374 return ERROR_FAIL;
375 }
376
377 /* update next place to put hardware watchpoint */
378 nds32_v3m->next_hwp_index--;
379 nds32_v3m->used_n_wp--;
380
381 return ERROR_OK;
382 }
383
384 struct nds32_v3_common_callback nds32_v3m_common_callback = {
385 .check_interrupt_stack = nds32_v3m_check_interrupt_stack,
386 .restore_interrupt_stack = nds32_v3m_restore_interrupt_stack,
387 .activate_hardware_breakpoint = nds32_v3m_activate_hardware_breakpoint,
388 .activate_hardware_watchpoint = nds32_v3m_activate_hardware_watchpoint,
389 .deactivate_hardware_breakpoint = nds32_v3m_deactivate_hardware_breakpoint,
390 .deactivate_hardware_watchpoint = nds32_v3m_deactivate_hardware_watchpoint,
391 };
392
393 static int nds32_v3m_target_create(struct target *target, Jim_Interp *interp)
394 {
395 struct nds32_v3m_common *nds32_v3m;
396
397 nds32_v3m = calloc(1, sizeof(*nds32_v3m));
398 if (!nds32_v3m)
399 return ERROR_FAIL;
400
401 nds32_v3_common_register_callback(&nds32_v3m_common_callback);
402 nds32_v3_target_create_common(target, &(nds32_v3m->nds32));
403
404 return ERROR_OK;
405 }
406
407 /* talk to the target and set things up */
408 static int nds32_v3m_examine(struct target *target)
409 {
410 struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
411 struct nds32 *nds32 = &(nds32_v3m->nds32);
412 struct aice_port_s *aice = target_to_aice(target);
413
414 if (!target_was_examined(target)) {
415 CHECK_RETVAL(nds32_edm_config(nds32));
416
417 if (nds32->reset_halt_as_examine)
418 CHECK_RETVAL(nds32_reset_halt(nds32));
419 }
420
421 uint32_t edm_cfg;
422 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
423
424 /* get the number of hardware breakpoints */
425 nds32_v3m->n_hbr = (edm_cfg & 0x7) + 1;
426 nds32_v3m->used_n_wp = 0;
427
428 /* get the number of hardware watchpoints */
429 /* If the WP field is hardwired to zero, it means this is a
430 * simple breakpoint. Otherwise, if the WP field is writable
431 * then it means this is a regular watchpoints. */
432 nds32_v3m->n_hwp = 0;
433 for (int32_t i = 0 ; i < nds32_v3m->n_hbr ; i++) {
434 /** check the hardware breakpoint is simple or not */
435 uint32_t tmp_value;
436 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + i, 0x1);
437 aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &tmp_value);
438
439 if (tmp_value)
440 nds32_v3m->n_hwp++;
441 }
442 /* hardware breakpoint is inserted from high index to low index */
443 nds32_v3m->next_hbr_index = nds32_v3m->n_hbr - 1;
444 /* hardware watchpoint is inserted from low index to high index */
445 nds32_v3m->next_hwp_index = 0;
446
447 LOG_INFO("%s: total hardware breakpoint %" PRId32 " (simple breakpoint %" PRId32 ")",
448 target_name(target), nds32_v3m->n_hbr, nds32_v3m->n_hbr - nds32_v3m->n_hwp);
449 LOG_INFO("%s: total hardware watchpoint %" PRId32, target_name(target), nds32_v3m->n_hwp);
450
451 nds32->target->state = TARGET_RUNNING;
452 nds32->target->debug_reason = DBG_REASON_NOTHALTED;
453
454 target_set_examined(target);
455
456 return ERROR_OK;
457 }
458
459 /** Holds methods for NDS32 V3m targets. */
460 struct target_type nds32_v3m_target = {
461 .name = "nds32_v3m",
462
463 .poll = nds32_poll,
464 .arch_state = nds32_arch_state,
465
466 .target_request_data = nds32_v3_target_request_data,
467
468 .halt = nds32_halt,
469 .resume = nds32_resume,
470 .step = nds32_step,
471
472 .assert_reset = nds32_assert_reset,
473 .deassert_reset = nds32_v3m_deassert_reset,
474
475 /* register access */
476 .get_gdb_reg_list = nds32_get_gdb_reg_list,
477
478 /* memory access */
479 .read_buffer = nds32_v3_read_buffer,
480 .write_buffer = nds32_v3_write_buffer,
481 .read_memory = nds32_v3_read_memory,
482 .write_memory = nds32_v3_write_memory,
483
484 .checksum_memory = nds32_v3_checksum_memory,
485
486 /* breakpoint/watchpoint */
487 .add_breakpoint = nds32_v3m_add_breakpoint,
488 .remove_breakpoint = nds32_v3m_remove_breakpoint,
489 .add_watchpoint = nds32_v3m_add_watchpoint,
490 .remove_watchpoint = nds32_v3m_remove_watchpoint,
491 .hit_watchpoint = nds32_v3_hit_watchpoint,
492
493 /* MMU */
494 .mmu = nds32_mmu,
495 .virt2phys = nds32_virtual_to_physical,
496 .read_phys_memory = nds32_read_phys_memory,
497 .write_phys_memory = nds32_write_phys_memory,
498
499 .run_algorithm = nds32_v3_run_algorithm,
500
501 .commands = nds32_command_handlers,
502 .target_create = nds32_v3m_target_create,
503 .init_target = nds32_v3_init_target,
504 .examine = nds32_v3m_examine,
505
506 .get_gdb_fileio_info = nds32_get_gdb_fileio_info,
507 .gdb_fileio_end = nds32_gdb_fileio_end,
508 };

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)