1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2013 Andes Technology *
5 * Hsiangkai Wang <hkwang@andestech.com> *
6 ***************************************************************************/
12 #include "breakpoints.h"
13 #include "nds32_cmd.h"
14 #include "nds32_aice.h"
16 #include "nds32_v3_common.h"
18 static int nds32_v3_activate_hardware_breakpoint(struct target
*target
)
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
;
25 for (bp
= target
->breakpoints
; bp
; bp
= bp
->next
) {
26 if (bp
->type
== BKPT_SOFT
) {
27 /* already set at nds32_v3_add_breakpoint() */
29 } else if (bp
->type
== BKPT_HARD
) {
32 aice_write_debug_reg(aice
, NDS_EDM_SR_BPA0
+ hbr_index
, bp
->address
);
34 aice_write_debug_reg(aice
, NDS_EDM_SR_BPAM0
+ hbr_index
, 0);
36 aice_write_debug_reg(aice
, NDS_EDM_SR_BPV0
+ hbr_index
, 0);
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);
42 /* enable breakpoint (physical address) */
43 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ hbr_index
, 0xA);
45 LOG_DEBUG("Add hardware BP %" PRId32
" at %08" TARGET_PRIxADDR
, hbr_index
,
55 static int nds32_v3_deactivate_hardware_breakpoint(struct target
*target
)
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
;
62 for (bp
= target
->breakpoints
; bp
; bp
= bp
->next
) {
63 if (bp
->type
== BKPT_SOFT
) {
65 } else if (bp
->type
== BKPT_HARD
) {
67 /* disable breakpoint */
68 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ hbr_index
, 0x0);
73 LOG_DEBUG("Remove hardware BP %" PRId32
" at %08" TARGET_PRIxADDR
, hbr_index
,
80 static int nds32_v3_activate_hardware_watchpoint(struct target
*target
)
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
;
86 uint32_t wp_config
= 0;
87 bool ld_stop
, st_stop
;
89 if (nds32_v3
->nds32
.global_stop
)
90 ld_stop
= st_stop
= false;
92 for (wp
= target
->watchpoints
; wp
; wp
= wp
->next
) {
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;
99 if (wp
->rw
== WPT_READ
)
101 else if (wp
->rw
== WPT_WRITE
)
103 else if (wp
->rw
== WPT_ACCESS
)
106 /* set/unset physical address bit of BPCn according to PSW.DT */
107 if (nds32_v3
->nds32
.memory
.address_translation
== false)
111 aice_write_debug_reg(aice
, NDS_EDM_SR_BPA0
+ wp_num
,
112 wp
->address
- (wp
->address
% wp
->length
));
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
);
118 aice_write_debug_reg(aice
, NDS_EDM_SR_BPV0
+ wp_num
, 0);
120 LOG_DEBUG("Add hardware watchpoint %" PRId32
" at %08" TARGET_PRIxADDR
" mask %08" PRIx32
,
121 wp_num
, wp
->address
, wp
->mask
);
124 } else if (nds32_v3
->nds32
.global_stop
) {
125 if (wp
->rw
== WPT_READ
)
127 else if (wp
->rw
== WPT_WRITE
)
129 else if (wp
->rw
== WPT_ACCESS
)
130 ld_stop
= st_stop
= true;
134 if (nds32_v3
->nds32
.global_stop
) {
136 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &edm_ctl
);
141 aice_write_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, edm_ctl
);
147 static int nds32_v3_deactivate_hardware_watchpoint(struct target
*target
)
149 struct aice_port_s
*aice
= target_to_aice(target
);
150 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
152 struct watchpoint
*wp
;
153 bool clean_global_stop
= false;
155 for (wp
= target
->watchpoints
; wp
; wp
= wp
->next
) {
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);
161 LOG_DEBUG("Remove hardware watchpoint %" PRId32
" at %08" TARGET_PRIxADDR
162 " mask %08" PRIx32
, wp_num
,
163 wp
->address
, wp
->mask
);
165 } else if (nds32_v3
->nds32
.global_stop
) {
166 clean_global_stop
= true;
170 if (clean_global_stop
) {
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
);
180 static int nds32_v3_check_interrupt_stack(struct nds32
*nds32
)
185 /* Save interrupt level */
186 nds32_get_mapped_reg(nds32
, IR0
, &val_ir0
);
187 nds32
->current_interrupt_level
= (val_ir0
>> 1) & 0x3;
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
);
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
);
200 static int nds32_v3_restore_interrupt_stack(struct nds32
*nds32
)
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
);
209 nds32_get_mapped_reg(nds32
, IR4
, &value
);
210 nds32_set_mapped_reg(nds32
, IR4
, value
);
212 nds32_get_mapped_reg(nds32
, IR6
, &value
);
213 nds32_set_mapped_reg(nds32
, IR6
, value
);
218 static int nds32_v3_deassert_reset(struct target
*target
)
221 struct aice_port_s
*aice
= target_to_aice(target
);
222 bool switch_to_v3_stack
= false;
223 uint32_t value_edm_ctl
;
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;
232 switch_to_v3_stack
= false;
234 CHECK_RETVAL(nds32_poll(target
));
236 if (target
->state
!= TARGET_HALTED
) {
238 LOG_WARNING("%s: ran after reset and before halt ...",
239 target_name(target
));
240 retval
= target_halt(target
);
241 if (retval
!= ERROR_OK
)
246 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
247 struct nds32
*nds32
= &(nds32_v3
->nds32
);
249 uint32_t interrupt_level
;
251 if (switch_to_v3_stack
== true) {
253 nds32_get_mapped_reg(nds32
, IR0
, &value
);
254 interrupt_level
= (value
>> 1) & 0x3;
257 value
|= (interrupt_level
<< 1);
258 value
|= 0x400; /* set PSW.DEX */
259 nds32_set_mapped_reg(nds32
, IR0
, value
);
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
);
272 static int nds32_v3_add_breakpoint(struct target
*target
,
273 struct breakpoint
*breakpoint
)
275 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
276 struct nds32
*nds32
= &(nds32_v3
->nds32
);
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
". -->",
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
;
295 /* update next place to put hardware breakpoint */
296 nds32_v3
->next_hbr_index
++;
298 /* hardware breakpoint insertion occurs before 'continue' actually */
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
;
308 return nds32_v3_add_breakpoint(target
, breakpoint
);
313 } else /* unrecognized breakpoint type */
319 static int nds32_v3_remove_breakpoint(struct target
*target
,
320 struct breakpoint
*breakpoint
)
322 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
324 if (breakpoint
->type
== BKPT_HARD
) {
325 if (nds32_v3
->next_hbr_index
<= 0)
328 /* update next place to put hardware breakpoint */
329 nds32_v3
->next_hbr_index
--;
331 /* hardware breakpoint removal occurs after 'halted' actually */
333 } else if (breakpoint
->type
== BKPT_SOFT
) {
334 return nds32_remove_software_breakpoint(target
, breakpoint
);
335 } else /* unrecognized breakpoint type */
341 static int nds32_v3_add_watchpoint(struct target
*target
,
342 struct watchpoint
*watchpoint
)
344 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
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. -->");
357 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
358 "breakpoints/watchpoints! The limit of combined "
359 "hardware breakpoints/watchpoints is %" PRId32
". -->",
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
);
367 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
370 /* update next place to put hardware watchpoint */
371 nds32_v3
->next_hbr_index
++;
372 nds32_v3
->used_n_wp
++;
377 static int nds32_v3_remove_watchpoint(struct target
*target
,
378 struct watchpoint
*watchpoint
)
380 struct nds32_v3_common
*nds32_v3
= target_to_nds32_v3(target
);
382 if (nds32_v3
->next_hbr_index
<= 0) {
383 if (nds32_v3
->nds32
.global_stop
)
389 /* update next place to put hardware breakpoint */
390 nds32_v3
->next_hbr_index
--;
391 nds32_v3
->used_n_wp
--;
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
,
405 static int nds32_v3_target_create(struct target
*target
, Jim_Interp
*interp
)
407 struct nds32_v3_common
*nds32_v3
;
409 nds32_v3
= calloc(1, sizeof(*nds32_v3
));
413 nds32_v3_common_register_callback(&nds32_v3_common_callback
);
414 nds32_v3_target_create_common(target
, &(nds32_v3
->nds32
));
419 /* talk to the target and set things up */
420 static int nds32_v3_examine(struct target
*target
)
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
);
426 if (!target_was_examined(target
)) {
427 CHECK_RETVAL(nds32_edm_config(nds32
));
429 if (nds32
->reset_halt_as_examine
)
430 CHECK_RETVAL(nds32_reset_halt(nds32
));
434 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CFG
, &edm_cfg
);
436 /* get the number of hardware breakpoints */
437 nds32_v3
->n_hbr
= (edm_cfg
& 0x7) + 1;
439 /* low interference profiling */
441 nds32_v3
->low_interference_profile
= true;
443 nds32_v3
->low_interference_profile
= false;
445 nds32_v3
->next_hbr_index
= 0;
446 nds32_v3
->used_n_wp
= 0;
448 LOG_INFO("%s: total hardware breakpoint %" PRId32
, target_name(target
),
451 nds32
->target
->state
= TARGET_RUNNING
;
452 nds32
->target
->debug_reason
= DBG_REASON_NOTHALTED
;
454 target_set_examined(target
);
459 /** Holds methods for Andes1337 targets. */
460 struct target_type nds32_v3_target
= {
464 .arch_state
= nds32_arch_state
,
466 .target_request_data
= nds32_v3_target_request_data
,
469 .resume
= nds32_resume
,
472 .assert_reset
= nds32_assert_reset
,
473 .deassert_reset
= nds32_v3_deassert_reset
,
475 /* register access */
476 .get_gdb_reg_list
= nds32_get_gdb_reg_list
,
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
,
484 .checksum_memory
= nds32_v3_checksum_memory
,
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
,
495 .virt2phys
= nds32_virtual_to_physical
,
496 .read_phys_memory
= nds32_read_phys_memory
,
497 .write_phys_memory
= nds32_write_phys_memory
,
499 .run_algorithm
= nds32_v3_run_algorithm
,
501 .commands
= nds32_command_handlers
,
502 .target_create
= nds32_v3_target_create
,
503 .init_target
= nds32_v3_init_target
,
504 .examine
= nds32_v3_examine
,
506 .get_gdb_fileio_info
= nds32_get_gdb_fileio_info
,
507 .gdb_fileio_end
= nds32_gdb_fileio_end
,
509 .profiling
= nds32_profiling
,
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)