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
,