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

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)