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"
15 #include "nds32_v3m.h"
16 #include "nds32_v3_common.h"
18 static int nds32_v3m_activate_hardware_breakpoint(struct target
*target
)
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;
25 for (bp
= target
->breakpoints
; bp
; bp
= bp
->next
) {
26 if (bp
->type
== BKPT_SOFT
) {
27 /* already set at nds32_v3m_add_breakpoint() */
29 } else if (bp
->type
== BKPT_HARD
) {
31 aice_write_debug_reg(aice
, NDS_EDM_SR_BPA0
+ brp_num
, bp
->address
);
33 aice_write_debug_reg(aice
, NDS_EDM_SR_BPAM0
+ brp_num
, 0);
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);
39 /* enable breakpoint (physical address) */
40 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ brp_num
, 0xA);
42 LOG_DEBUG("Add hardware BP %u at %08" TARGET_PRIxADDR
, brp_num
,
54 static int nds32_v3m_deactivate_hardware_breakpoint(struct target
*target
)
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;
61 for (bp
= target
->breakpoints
; bp
; bp
= bp
->next
) {
62 if (bp
->type
== BKPT_SOFT
)
64 else if (bp
->type
== BKPT_HARD
)
65 /* disable breakpoint */
66 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ brp_num
, 0x0);
70 LOG_DEBUG("Remove hardware BP %u at %08" TARGET_PRIxADDR
, brp_num
,
79 static int nds32_v3m_activate_hardware_watchpoint(struct target
*target
)
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
;
85 uint32_t wp_config
= 0;
86 bool ld_stop
, st_stop
;
88 if (nds32_v3m
->nds32
.global_stop
)
89 ld_stop
= st_stop
= false;
91 for (wp
= target
->watchpoints
; wp
; wp
= wp
->next
) {
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;
98 if (wp
->rw
== WPT_READ
)
100 else if (wp
->rw
== WPT_WRITE
)
102 else if (wp
->rw
== WPT_ACCESS
)
105 /* set/unset physical address bit of BPCn according to PSW.DT */
106 if (nds32_v3m
->nds32
.memory
.address_translation
== false)
110 aice_write_debug_reg(aice
, NDS_EDM_SR_BPA0
+ wp_num
,
111 wp
->address
- (wp
->address
% wp
->length
));
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
);
117 LOG_DEBUG("Add hardware watchpoint %" PRId32
" at %08" TARGET_PRIxADDR
118 " mask %08" PRIx32
, wp_num
, wp
->address
, wp
->mask
);
121 } else if (nds32_v3m
->nds32
.global_stop
) {
122 if (wp
->rw
== WPT_READ
)
124 else if (wp
->rw
== WPT_WRITE
)
126 else if (wp
->rw
== WPT_ACCESS
)
127 ld_stop
= st_stop
= true;
131 if (nds32_v3m
->nds32
.global_stop
) {
133 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &edm_ctl
);
138 aice_write_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, edm_ctl
);
144 static int nds32_v3m_deactivate_hardware_watchpoint(struct target
*target
)
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
;
150 bool clean_global_stop
= false;
152 for (wp
= target
->watchpoints
; wp
; wp
= wp
->next
) {
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);
158 LOG_DEBUG("Remove hardware watchpoint %" PRId32
" at %08" TARGET_PRIxADDR
159 " mask %08" PRIx32
, wp_num
, wp
->address
, wp
->mask
);
161 } else if (nds32_v3m
->nds32
.global_stop
) {
162 clean_global_stop
= true;
166 if (clean_global_stop
) {
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
);
176 static int nds32_v3m_check_interrupt_stack(struct nds32
*nds32
)
181 /* Save interrupt level */
182 nds32_get_mapped_reg(nds32
, IR0
, &val_ir0
);
183 nds32
->current_interrupt_level
= (val_ir0
>> 1) & 0x3;
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
);
189 /* backup $ir6 to avoid suppressed exception overwrite */
190 nds32_get_mapped_reg(nds32
, IR6
, &value
);
195 static int nds32_v3m_restore_interrupt_stack(struct nds32
*nds32
)
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
);
204 nds32_get_mapped_reg(nds32
, IR6
, &value
);
205 nds32_set_mapped_reg(nds32
, IR6
, value
);
210 static int nds32_v3m_deassert_reset(struct target
*target
)
214 CHECK_RETVAL(nds32_poll(target
));
216 if (target
->state
!= TARGET_HALTED
) {
218 LOG_WARNING("%s: ran after reset and before halt ...",
219 target_name(target
));
220 retval
= target_halt(target
);
221 if (retval
!= ERROR_OK
)
229 static int nds32_v3m_add_breakpoint(struct target
*target
,
230 struct breakpoint
*breakpoint
)
232 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
233 struct nds32
*nds32
= &(nds32_v3m
->nds32
);
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
". -->",
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
;
252 /* update next place to put hardware breakpoint */
253 nds32_v3m
->next_hbr_index
--;
255 /* hardware breakpoint insertion occurs before 'continue' actually */
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
;
265 return nds32_v3m_add_breakpoint(target
, breakpoint
);
270 } else /* unrecognized breakpoint type */
276 static int nds32_v3m_remove_breakpoint(struct target
*target
,
277 struct breakpoint
*breakpoint
)
279 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
281 if (breakpoint
->type
== BKPT_HARD
) {
282 if (nds32_v3m
->next_hbr_index
>= nds32_v3m
->n_hbr
- 1)
285 /* update next place to put hardware breakpoint */
286 nds32_v3m
->next_hbr_index
++;
288 /* hardware breakpoint removal occurs after 'halted' actually */
290 } else if (breakpoint
->type
== BKPT_SOFT
) {
291 return nds32_remove_software_breakpoint(target
, breakpoint
);
292 } else /* unrecognized breakpoint type */
298 static int nds32_v3m_add_watchpoint(struct target
*target
,
299 struct watchpoint
*watchpoint
)
301 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
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. -->");
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
;
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. -->");
333 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
334 "breakpoints/watchpoints! The limit of combined "
335 "hardware breakpoints/watchpoints is %" PRId32
". -->",
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
;
345 /* update next place to put hardware watchpoint */
346 nds32_v3m
->next_hwp_index
++;
347 nds32_v3m
->used_n_wp
++;
352 static int nds32_v3m_remove_watchpoint(struct target
*target
,
353 struct watchpoint
*watchpoint
)
355 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
357 if (nds32_v3m
->next_hwp_index
<= 0) {
358 if (nds32_v3m
->nds32
.global_stop
)
364 /* update next place to put hardware watchpoint */
365 nds32_v3m
->next_hwp_index
--;
366 nds32_v3m
->used_n_wp
--;
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
,
380 static int nds32_v3m_target_create(struct target
*target
, Jim_Interp
*interp
)
382 struct nds32_v3m_common
*nds32_v3m
;
384 nds32_v3m
= calloc(1, sizeof(*nds32_v3m
));
388 nds32_v3_common_register_callback(&nds32_v3m_common_callback
);
389 nds32_v3_target_create_common(target
, &(nds32_v3m
->nds32
));
394 /* talk to the target and set things up */
395 static int nds32_v3m_examine(struct target
*target
)
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
);
401 if (!target_was_examined(target
)) {
402 CHECK_RETVAL(nds32_edm_config(nds32
));
404 if (nds32
->reset_halt_as_examine
)
405 CHECK_RETVAL(nds32_reset_halt(nds32
));
409 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CFG
, &edm_cfg
);
411 /* get the number of hardware breakpoints */
412 nds32_v3m
->n_hbr
= (edm_cfg
& 0x7) + 1;
413 nds32_v3m
->used_n_wp
= 0;
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 */
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
);
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;
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
);
438 nds32
->target
->state
= TARGET_RUNNING
;
439 nds32
->target
->debug_reason
= DBG_REASON_NOTHALTED
;
441 target_set_examined(target
);
446 /** Holds methods for NDS32 V3m targets. */
447 struct target_type nds32_v3m_target
= {
451 .arch_state
= nds32_arch_state
,
453 .target_request_data
= nds32_v3_target_request_data
,
456 .resume
= nds32_resume
,
459 .assert_reset
= nds32_assert_reset
,
460 .deassert_reset
= nds32_v3m_deassert_reset
,
462 /* register access */
463 .get_gdb_reg_list
= nds32_get_gdb_reg_list
,
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
,
471 .checksum_memory
= nds32_v3_checksum_memory
,
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
,
482 .virt2phys
= nds32_virtual_to_physical
,
483 .read_phys_memory
= nds32_read_phys_memory
,
484 .write_phys_memory
= nds32_write_phys_memory
,
486 .run_algorithm
= nds32_v3_run_algorithm
,
488 .commands
= nds32_command_handlers
,
489 .target_create
= nds32_v3m_target_create
,
490 .init_target
= nds32_v3_init_target
,
491 .examine
= nds32_v3m_examine
,
493 .get_gdb_fileio_info
= nds32_get_gdb_fileio_info
,
494 .gdb_fileio_end
= nds32_gdb_fileio_end
,