nds32: Fix typo in debug log
[openocd.git] / src / target / nds32_v3.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, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "breakpoints.h"
24 #include "nds32_cmd.h"
25 #include "nds32_aice.h"
26 #include "nds32_v3.h"
27 #include "nds32_v3_common.h"
28
29 static int nds32_v3_activate_hardware_breakpoint(struct target *target)
30 {
31 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
32 struct aice_port_s *aice = target_to_aice(target);
33 struct breakpoint *bp;
34 int32_t hbr_index = nds32_v3->next_hbr_index;
35
36 for (bp = target->breakpoints; bp; bp = bp->next) {
37 if (bp->type == BKPT_SOFT) {
38 /* already set at nds32_v3_add_breakpoint() */
39 continue;
40 } else if (bp->type == BKPT_HARD) {
41 hbr_index--;
42 /* set address */
43 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + hbr_index, bp->address);
44 /* set mask */
45 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + hbr_index, 0);
46 /* set value */
47 aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + hbr_index, 0);
48
49 if (nds32_v3->nds32.memory.address_translation)
50 /* enable breakpoint (virtual address) */
51 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x2);
52 else
53 /* enable breakpoint (physical address) */
54 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0xA);
55
56 LOG_DEBUG("Add hardware BP %" PRId32 " at %08" PRIx32, hbr_index,
57 bp->address);
58 } else {
59 return ERROR_FAIL;
60 }
61 }
62
63 return ERROR_OK;
64 }
65
66 static int nds32_v3_deactivate_hardware_breakpoint(struct target *target)
67 {
68 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
69 struct aice_port_s *aice = target_to_aice(target);
70 struct breakpoint *bp;
71 int32_t hbr_index = nds32_v3->next_hbr_index;
72
73 for (bp = target->breakpoints; bp; bp = bp->next) {
74 if (bp->type == BKPT_SOFT) {
75 continue;
76 } else if (bp->type == BKPT_HARD) {
77 hbr_index--;
78 /* disable breakpoint */
79 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x0);
80 } else {
81 return ERROR_FAIL;
82 }
83
84 LOG_DEBUG("Remove hardware BP %" PRId32 " at %08" PRIx32, hbr_index,
85 bp->address);
86 }
87
88 return ERROR_OK;
89 }
90
91 static int nds32_v3_activate_hardware_watchpoint(struct target *target)
92 {
93 struct aice_port_s *aice = target_to_aice(target);
94 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
95 struct watchpoint *wp;
96 int32_t wp_num = 0;
97 uint32_t wp_config = 0;
98 bool ld_stop, st_stop;
99
100 if (nds32_v3->nds32.global_stop)
101 ld_stop = st_stop = false;
102
103 for (wp = target->watchpoints; wp; wp = wp->next) {
104
105 if (wp_num < nds32_v3->used_n_wp) {
106 wp->mask = wp->length - 1;
107 if ((wp->address % wp->length) != 0)
108 wp->mask = (wp->mask << 1) + 1;
109
110 if (wp->rw == WPT_READ)
111 wp_config = 0x3;
112 else if (wp->rw == WPT_WRITE)
113 wp_config = 0x5;
114 else if (wp->rw == WPT_ACCESS)
115 wp_config = 0x7;
116
117 /* set/unset physical address bit of BPCn according to PSW.DT */
118 if (nds32_v3->nds32.memory.address_translation == false)
119 wp_config |= 0x8;
120
121 /* set address */
122 aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
123 wp->address - (wp->address % wp->length));
124 /* set mask */
125 aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
126 /* enable watchpoint */
127 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
128 /* set value */
129 aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + wp_num, 0);
130
131 LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" PRIx32 " mask %08" PRIx32,
132 wp_num, wp->address, wp->mask);
133
134 wp_num++;
135 } else if (nds32_v3->nds32.global_stop) {
136 if (wp->rw == WPT_READ)
137 ld_stop = true;
138 else if (wp->rw == WPT_WRITE)
139 st_stop = true;
140 else if (wp->rw == WPT_ACCESS)
141 ld_stop = st_stop = true;
142 }
143 }
144
145 if (nds32_v3->nds32.global_stop) {
146 uint32_t edm_ctl;
147 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
148 if (ld_stop)
149 edm_ctl |= 0x10;
150 if (st_stop)
151 edm_ctl |= 0x20;
152 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
153 }
154
155 return ERROR_OK;
156 }
157
158 static int nds32_v3_deactivate_hardware_watchpoint(struct target *target)
159 {
160 struct aice_port_s *aice = target_to_aice(target);
161 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
162 int32_t wp_num = 0;
163 struct watchpoint *wp;
164 bool clean_global_stop = false;
165
166 for (wp = target->watchpoints; wp; wp = wp->next) {
167
168 if (wp_num < nds32_v3->used_n_wp) {
169 /* disable watchpoint */
170 aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
171
172 LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" PRIx32
173 " mask %08" PRIx32, wp_num,
174 wp->address, wp->mask);
175 wp_num++;
176 } else if (nds32_v3->nds32.global_stop) {
177 clean_global_stop = true;
178 }
179 }
180
181 if (clean_global_stop) {
182 uint32_t edm_ctl;
183 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
184 edm_ctl = edm_ctl & (~0x30);
185 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
186 }
187
188 return ERROR_OK;
189 }
190
191 static int nds32_v3_check_interrupt_stack(struct nds32 *nds32)
192 {
193 uint32_t val_ir0;
194 uint32_t value;
195
196 /* Save interrupt level */
197 nds32_get_mapped_reg(nds32, IR0, &val_ir0);
198 nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
199
200 if (nds32_reach_max_interrupt_level(nds32))
201 LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->",
202 nds32->current_interrupt_level);
203
204 /* backup $ir4 & $ir6 to avoid suppressed exception overwrite */
205 nds32_get_mapped_reg(nds32, IR4, &value);
206 nds32_get_mapped_reg(nds32, IR6, &value);
207
208 return ERROR_OK;
209 }
210
211 static int nds32_v3_restore_interrupt_stack(struct nds32 *nds32)
212 {
213 uint32_t value;
214
215 /* get backup value from cache */
216 /* then set back to make the register dirty */
217 nds32_get_mapped_reg(nds32, IR0, &value);
218 nds32_set_mapped_reg(nds32, IR0, value);
219
220 nds32_get_mapped_reg(nds32, IR4, &value);
221 nds32_set_mapped_reg(nds32, IR4, value);
222
223 nds32_get_mapped_reg(nds32, IR6, &value);
224 nds32_set_mapped_reg(nds32, IR6, value);
225
226 return ERROR_OK;
227 }
228
229 static int nds32_v3_deassert_reset(struct target *target)
230 {
231 int retval;
232 struct aice_port_s *aice = target_to_aice(target);
233 bool switch_to_v3_stack = false;
234 uint32_t value_edm_ctl;
235
236 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &value_edm_ctl);
237 if (((value_edm_ctl >> 6) & 0x1) == 0) { /* reset to V2 EDM mode */
238 aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, value_edm_ctl | (0x1 << 6));
239 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &value_edm_ctl);
240 if (((value_edm_ctl >> 6) & 0x1) == 1)
241 switch_to_v3_stack = true;
242 } else
243 switch_to_v3_stack = false;
244
245 CHECK_RETVAL(nds32_poll(target));
246
247 if (target->state != TARGET_HALTED) {
248 /* reset only */
249 LOG_WARNING("%s: ran after reset and before halt ...",
250 target_name(target));
251 retval = target_halt(target);
252 if (retval != ERROR_OK)
253 return retval;
254
255 } else {
256 /* reset-halt */
257 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
258 struct nds32 *nds32 = &(nds32_v3->nds32);
259 uint32_t value;
260 uint32_t interrupt_level;
261
262 if (switch_to_v3_stack == true) {
263 /* PSW.INTL-- */
264 nds32_get_mapped_reg(nds32, IR0, &value);
265 interrupt_level = (value >> 1) & 0x3;
266 interrupt_level--;
267 value &= ~(0x6);
268 value |= (interrupt_level << 1);
269 value |= 0x400; /* set PSW.DEX */
270 nds32_set_mapped_reg(nds32, IR0, value);
271
272 /* copy IPC to OIPC */
273 if ((interrupt_level + 1) < nds32->max_interrupt_level) {
274 nds32_get_mapped_reg(nds32, IR9, &value);
275 nds32_set_mapped_reg(nds32, IR11, value);
276 }
277 }
278 }
279
280 return ERROR_OK;
281 }
282
283 static int nds32_v3_add_breakpoint(struct target *target,
284 struct breakpoint *breakpoint)
285 {
286 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
287 struct nds32 *nds32 = &(nds32_v3->nds32);
288 int result;
289
290 if (breakpoint->type == BKPT_HARD) {
291 /* check hardware resource */
292 if (nds32_v3->n_hbr <= nds32_v3->next_hbr_index) {
293 LOG_WARNING("<-- TARGET WARNING! Insert too many "
294 "hardware breakpoints/watchpoints! "
295 "The limit of combined hardware "
296 "breakpoints/watchpoints is %" PRId32 ". -->",
297 nds32_v3->n_hbr);
298 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
299 "hardware breakpoint: %" PRId32 ", hardware "
300 "watchpoints: %" PRId32 ". -->",
301 nds32_v3->next_hbr_index - nds32_v3->used_n_wp,
302 nds32_v3->used_n_wp);
303 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
304 }
305
306 /* update next place to put hardware breakpoint */
307 nds32_v3->next_hbr_index++;
308
309 /* hardware breakpoint insertion occurs before 'continue' actually */
310 return ERROR_OK;
311 } else if (breakpoint->type == BKPT_SOFT) {
312 result = nds32_add_software_breakpoint(target, breakpoint);
313 if (ERROR_OK != result) {
314 /* auto convert to hardware breakpoint if failed */
315 if (nds32->auto_convert_hw_bp) {
316 /* convert to hardware breakpoint */
317 breakpoint->type = BKPT_HARD;
318
319 return nds32_v3_add_breakpoint(target, breakpoint);
320 }
321 }
322
323 return result;
324 } else /* unrecognized breakpoint type */
325 return ERROR_FAIL;
326
327 return ERROR_OK;
328 }
329
330 static int nds32_v3_remove_breakpoint(struct target *target,
331 struct breakpoint *breakpoint)
332 {
333 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
334
335 if (breakpoint->type == BKPT_HARD) {
336 if (nds32_v3->next_hbr_index <= 0)
337 return ERROR_FAIL;
338
339 /* update next place to put hardware breakpoint */
340 nds32_v3->next_hbr_index--;
341
342 /* hardware breakpoint removal occurs after 'halted' actually */
343 return ERROR_OK;
344 } else if (breakpoint->type == BKPT_SOFT) {
345 return nds32_remove_software_breakpoint(target, breakpoint);
346 } else /* unrecognized breakpoint type */
347 return ERROR_FAIL;
348
349 return ERROR_OK;
350 }
351
352 static int nds32_v3_add_watchpoint(struct target *target,
353 struct watchpoint *watchpoint)
354 {
355 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
356
357 /* check hardware resource */
358 if (nds32_v3->n_hbr <= nds32_v3->next_hbr_index) {
359 /* No hardware resource */
360 if (nds32_v3->nds32.global_stop) {
361 LOG_WARNING("<-- TARGET WARNING! The number of "
362 "watchpoints exceeds the hardware "
363 "resources. Stop at every load/store "
364 "instruction to check for watchpoint matches. -->");
365 return ERROR_OK;
366 }
367
368 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
369 "breakpoints/watchpoints! The limit of combined "
370 "hardware breakpoints/watchpoints is %" PRId32 ". -->",
371 nds32_v3->n_hbr);
372 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
373 "hardware breakpoint: %" PRId32 ", hardware "
374 "watchpoints: %" PRId32 ". -->",
375 nds32_v3->next_hbr_index - nds32_v3->used_n_wp,
376 nds32_v3->used_n_wp);
377
378 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
379 }
380
381 /* update next place to put hardware watchpoint */
382 nds32_v3->next_hbr_index++;
383 nds32_v3->used_n_wp++;
384
385 return ERROR_OK;
386 }
387
388 static int nds32_v3_remove_watchpoint(struct target *target,
389 struct watchpoint *watchpoint)
390 {
391 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
392
393 if (nds32_v3->next_hbr_index <= 0) {
394 if (nds32_v3->nds32.global_stop)
395 return ERROR_OK;
396
397 return ERROR_FAIL;
398 }
399
400 /* update next place to put hardware breakpoint */
401 nds32_v3->next_hbr_index--;
402 nds32_v3->used_n_wp--;
403
404 return ERROR_OK;
405 }
406
407 struct nds32_v3_common_callback nds32_v3_common_callback = {
408 .check_interrupt_stack = nds32_v3_check_interrupt_stack,
409 .restore_interrupt_stack = nds32_v3_restore_interrupt_stack,
410 .activate_hardware_breakpoint = nds32_v3_activate_hardware_breakpoint,
411 .activate_hardware_watchpoint = nds32_v3_activate_hardware_watchpoint,
412 .deactivate_hardware_breakpoint = nds32_v3_deactivate_hardware_breakpoint,
413 .deactivate_hardware_watchpoint = nds32_v3_deactivate_hardware_watchpoint,
414 };
415
416 static int nds32_v3_target_create(struct target *target, Jim_Interp *interp)
417 {
418 struct nds32_v3_common *nds32_v3;
419
420 nds32_v3 = calloc(1, sizeof(*nds32_v3));
421 if (!nds32_v3)
422 return ERROR_FAIL;
423
424 nds32_v3_common_register_callback(&nds32_v3_common_callback);
425 nds32_v3_target_create_common(target, &(nds32_v3->nds32));
426
427 return ERROR_OK;
428 }
429
430 /* talk to the target and set things up */
431 static int nds32_v3_examine(struct target *target)
432 {
433 struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
434 struct nds32 *nds32 = &(nds32_v3->nds32);
435 struct aice_port_s *aice = target_to_aice(target);
436
437 if (!target_was_examined(target)) {
438 CHECK_RETVAL(nds32_edm_config(nds32));
439
440 if (nds32->reset_halt_as_examine)
441 CHECK_RETVAL(nds32_reset_halt(nds32));
442 }
443
444 uint32_t edm_cfg;
445 aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
446
447 /* get the number of hardware breakpoints */
448 nds32_v3->n_hbr = (edm_cfg & 0x7) + 1;
449
450 /* low interference profiling */
451 if (edm_cfg & 0x100)
452 nds32_v3->low_interference_profile = true;
453 else
454 nds32_v3->low_interference_profile = false;
455
456 nds32_v3->next_hbr_index = 0;
457 nds32_v3->used_n_wp = 0;
458
459 LOG_INFO("%s: total hardware breakpoint %" PRId32, target_name(target),
460 nds32_v3->n_hbr);
461
462 nds32->target->state = TARGET_RUNNING;
463 nds32->target->debug_reason = DBG_REASON_NOTHALTED;
464
465 target_set_examined(target);
466
467 return ERROR_OK;
468 }
469
470 /** Holds methods for Andes1337 targets. */
471 struct target_type nds32_v3_target = {
472 .name = "nds32_v3",
473
474 .poll = nds32_poll,
475 .arch_state = nds32_arch_state,
476
477 .target_request_data = nds32_v3_target_request_data,
478
479 .halt = nds32_halt,
480 .resume = nds32_resume,
481 .step = nds32_step,
482
483 .assert_reset = nds32_assert_reset,
484 .deassert_reset = nds32_v3_deassert_reset,
485
486 /* register access */
487 .get_gdb_reg_list = nds32_get_gdb_reg_list,
488
489 /* memory access */
490 .read_buffer = nds32_v3_read_buffer,
491 .write_buffer = nds32_v3_write_buffer,
492 .read_memory = nds32_v3_read_memory,
493 .write_memory = nds32_v3_write_memory,
494
495 .checksum_memory = nds32_v3_checksum_memory,
496
497 /* breakpoint/watchpoint */
498 .add_breakpoint = nds32_v3_add_breakpoint,
499 .remove_breakpoint = nds32_v3_remove_breakpoint,
500 .add_watchpoint = nds32_v3_add_watchpoint,
501 .remove_watchpoint = nds32_v3_remove_watchpoint,
502 .hit_watchpoint = nds32_v3_hit_watchpoint,
503
504 /* MMU */
505 .mmu = nds32_mmu,
506 .virt2phys = nds32_virtual_to_physical,
507 .read_phys_memory = nds32_read_phys_memory,
508 .write_phys_memory = nds32_write_phys_memory,
509
510 .run_algorithm = nds32_v3_run_algorithm,
511
512 .commands = nds32_command_handlers,
513 .target_create = nds32_v3_target_create,
514 .init_target = nds32_v3_init_target,
515 .examine = nds32_v3_examine,
516
517 .get_gdb_fileio_info = nds32_get_gdb_fileio_info,
518 .gdb_fileio_end = nds32_gdb_fileio_end,
519
520 .profiling = nds32_profiling,
521 };

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)