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

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)