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

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)