1 /***************************************************************************
2 * Copyright (C) 2013 Andes Technology *
3 * Hsiangkai Wang <hkwang@andestech.com> *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
23 #include "breakpoints.h"
24 #include "nds32_cmd.h"
25 #include "nds32_aice.h"
26 #include "nds32_v3m.h"
27 #include "nds32_v3_common.h"
29 static int nds32_v3m_activate_hardware_breakpoint(struct target
*target
)
31 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
32 struct aice_port_s
*aice
= target_to_aice(target
);
33 struct breakpoint
*bp
;
34 unsigned brp_num
= nds32_v3m
->n_hbr
- 1;
36 for (bp
= target
->breakpoints
; bp
; bp
= bp
->next
) {
37 if (bp
->type
== BKPT_SOFT
) {
38 /* already set at nds32_v3m_add_breakpoint() */
40 } else if (bp
->type
== BKPT_HARD
) {
42 aice_write_debug_reg(aice
, NDS_EDM_SR_BPA0
+ brp_num
, bp
->address
);
44 aice_write_debug_reg(aice
, NDS_EDM_SR_BPAM0
+ brp_num
, 0);
46 if (nds32_v3m
->nds32
.memory
.address_translation
)
47 /* enable breakpoint (virtual address) */
48 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ brp_num
, 0x2);
50 /* enable breakpoint (physical address) */
51 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ brp_num
, 0xA);
53 LOG_DEBUG("Add hardware BP %u at %08" TARGET_PRIxADDR
, brp_num
,
65 static int nds32_v3m_deactivate_hardware_breakpoint(struct target
*target
)
67 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
68 struct aice_port_s
*aice
= target_to_aice(target
);
69 struct breakpoint
*bp
;
70 unsigned brp_num
= nds32_v3m
->n_hbr
- 1;
72 for (bp
= target
->breakpoints
; bp
; bp
= bp
->next
) {
73 if (bp
->type
== BKPT_SOFT
)
75 else if (bp
->type
== BKPT_HARD
)
76 /* disable breakpoint */
77 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ brp_num
, 0x0);
81 LOG_DEBUG("Remove hardware BP %u at %08" TARGET_PRIxADDR
, brp_num
,
90 static int nds32_v3m_activate_hardware_watchpoint(struct target
*target
)
92 struct aice_port_s
*aice
= target_to_aice(target
);
93 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
94 struct watchpoint
*wp
;
96 uint32_t wp_config
= 0;
97 bool ld_stop
, st_stop
;
99 if (nds32_v3m
->nds32
.global_stop
)
100 ld_stop
= st_stop
= false;
102 for (wp
= target
->watchpoints
; wp
; wp
= wp
->next
) {
104 if (wp_num
< nds32_v3m
->used_n_wp
) {
105 wp
->mask
= wp
->length
- 1;
106 if ((wp
->address
% wp
->length
) != 0)
107 wp
->mask
= (wp
->mask
<< 1) + 1;
109 if (wp
->rw
== WPT_READ
)
111 else if (wp
->rw
== WPT_WRITE
)
113 else if (wp
->rw
== WPT_ACCESS
)
116 /* set/unset physical address bit of BPCn according to PSW.DT */
117 if (nds32_v3m
->nds32
.memory
.address_translation
== false)
121 aice_write_debug_reg(aice
, NDS_EDM_SR_BPA0
+ wp_num
,
122 wp
->address
- (wp
->address
% wp
->length
));
124 aice_write_debug_reg(aice
, NDS_EDM_SR_BPAM0
+ wp_num
, wp
->mask
);
125 /* enable watchpoint */
126 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ wp_num
, wp_config
);
128 LOG_DEBUG("Add hardware watchpoint %" PRId32
" at %08" TARGET_PRIxADDR
129 " mask %08" PRIx32
, wp_num
, wp
->address
, wp
->mask
);
132 } else if (nds32_v3m
->nds32
.global_stop
) {
133 if (wp
->rw
== WPT_READ
)
135 else if (wp
->rw
== WPT_WRITE
)
137 else if (wp
->rw
== WPT_ACCESS
)
138 ld_stop
= st_stop
= true;
142 if (nds32_v3m
->nds32
.global_stop
) {
144 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &edm_ctl
);
149 aice_write_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, edm_ctl
);
155 static int nds32_v3m_deactivate_hardware_watchpoint(struct target
*target
)
157 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
158 struct aice_port_s
*aice
= target_to_aice(target
);
159 struct watchpoint
*wp
;
161 bool clean_global_stop
= false;
163 for (wp
= target
->watchpoints
; wp
; wp
= wp
->next
) {
165 if (wp_num
< nds32_v3m
->used_n_wp
) {
166 /* disable watchpoint */
167 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ wp_num
, 0x0);
169 LOG_DEBUG("Remove hardware watchpoint %" PRId32
" at %08" TARGET_PRIxADDR
170 " mask %08" PRIx32
, wp_num
, wp
->address
, wp
->mask
);
172 } else if (nds32_v3m
->nds32
.global_stop
) {
173 clean_global_stop
= true;
177 if (clean_global_stop
) {
179 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, &edm_ctl
);
180 edm_ctl
= edm_ctl
& (~0x30);
181 aice_write_debug_reg(aice
, NDS_EDM_SR_EDM_CTL
, edm_ctl
);
187 static int nds32_v3m_check_interrupt_stack(struct nds32
*nds32
)
192 /* Save interrupt level */
193 nds32_get_mapped_reg(nds32
, IR0
, &val_ir0
);
194 nds32
->current_interrupt_level
= (val_ir0
>> 1) & 0x3;
196 if (nds32_reach_max_interrupt_level(nds32
))
197 LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32
". -->",
198 nds32
->current_interrupt_level
);
200 /* backup $ir6 to avoid suppressed exception overwrite */
201 nds32_get_mapped_reg(nds32
, IR6
, &value
);
206 static int nds32_v3m_restore_interrupt_stack(struct nds32
*nds32
)
210 /* get backup value from cache */
211 /* then set back to make the register dirty */
212 nds32_get_mapped_reg(nds32
, IR0
, &value
);
213 nds32_set_mapped_reg(nds32
, IR0
, value
);
215 nds32_get_mapped_reg(nds32
, IR6
, &value
);
216 nds32_set_mapped_reg(nds32
, IR6
, value
);
221 static int nds32_v3m_deassert_reset(struct target
*target
)
225 CHECK_RETVAL(nds32_poll(target
));
227 if (target
->state
!= TARGET_HALTED
) {
229 LOG_WARNING("%s: ran after reset and before halt ...",
230 target_name(target
));
231 retval
= target_halt(target
);
232 if (retval
!= ERROR_OK
)
240 static int nds32_v3m_add_breakpoint(struct target
*target
,
241 struct breakpoint
*breakpoint
)
243 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
244 struct nds32
*nds32
= &(nds32_v3m
->nds32
);
247 if (breakpoint
->type
== BKPT_HARD
) {
248 /* check hardware resource */
249 if (nds32_v3m
->next_hbr_index
< nds32_v3m
->next_hwp_index
) {
250 LOG_WARNING("<-- TARGET WARNING! Insert too many "
251 "hardware breakpoints/watchpoints! "
252 "The limit of combined hardware "
253 "breakpoints/watchpoints is %" PRId32
". -->",
255 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
256 "hardware breakpoint: %" PRId32
", hardware "
257 "watchpoints: %" PRId32
". -->",
258 nds32_v3m
->n_hbr
- nds32_v3m
->next_hbr_index
- 1,
259 nds32_v3m
->used_n_wp
);
260 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
263 /* update next place to put hardware breakpoint */
264 nds32_v3m
->next_hbr_index
--;
266 /* hardware breakpoint insertion occurs before 'continue' actually */
268 } else if (breakpoint
->type
== BKPT_SOFT
) {
269 result
= nds32_add_software_breakpoint(target
, breakpoint
);
270 if (ERROR_OK
!= result
) {
271 /* auto convert to hardware breakpoint if failed */
272 if (nds32
->auto_convert_hw_bp
) {
273 /* convert to hardware breakpoint */
274 breakpoint
->type
= BKPT_HARD
;
276 return nds32_v3m_add_breakpoint(target
, breakpoint
);
281 } else /* unrecognized breakpoint type */
287 static int nds32_v3m_remove_breakpoint(struct target
*target
,
288 struct breakpoint
*breakpoint
)
290 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
292 if (breakpoint
->type
== BKPT_HARD
) {
293 if (nds32_v3m
->next_hbr_index
>= nds32_v3m
->n_hbr
- 1)
296 /* update next place to put hardware breakpoint */
297 nds32_v3m
->next_hbr_index
++;
299 /* hardware breakpoint removal occurs after 'halted' actually */
301 } else if (breakpoint
->type
== BKPT_SOFT
) {
302 return nds32_remove_software_breakpoint(target
, breakpoint
);
303 } else /* unrecognized breakpoint type */
309 static int nds32_v3m_add_watchpoint(struct target
*target
,
310 struct watchpoint
*watchpoint
)
312 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
314 /* check hardware resource */
315 if (nds32_v3m
->next_hwp_index
>= nds32_v3m
->n_hwp
) {
316 /* No hardware resource */
317 if (nds32_v3m
->nds32
.global_stop
) {
318 LOG_WARNING("<-- TARGET WARNING! The number of "
319 "watchpoints exceeds the hardware "
320 "resources. Stop at every load/store "
321 "instruction to check for watchpoint matches. -->");
325 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
326 "watchpoints! The limit of hardware watchpoints "
327 "is %" PRId32
". -->", nds32_v3m
->n_hwp
);
328 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
329 "hardware watchpoint: %" PRId32
". -->",
330 nds32_v3m
->used_n_wp
);
331 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
334 if (nds32_v3m
->next_hwp_index
> nds32_v3m
->next_hbr_index
) {
335 /* No hardware resource */
336 if (nds32_v3m
->nds32
.global_stop
) {
337 LOG_WARNING("<-- TARGET WARNING! The number of "
338 "watchpoints exceeds the hardware "
339 "resources. Stop at every load/store "
340 "instruction to check for watchpoint matches. -->");
344 LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
345 "breakpoints/watchpoints! The limit of combined "
346 "hardware breakpoints/watchpoints is %" PRId32
". -->",
348 LOG_WARNING("<-- TARGET STATUS: Inserted number of "
349 "hardware breakpoint: %" PRId32
", hardware "
350 "watchpoints: %" PRId32
". -->",
351 nds32_v3m
->n_hbr
- nds32_v3m
->next_hbr_index
- 1,
352 nds32_v3m
->used_n_wp
);
353 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
356 /* update next place to put hardware watchpoint */
357 nds32_v3m
->next_hwp_index
++;
358 nds32_v3m
->used_n_wp
++;
363 static int nds32_v3m_remove_watchpoint(struct target
*target
,
364 struct watchpoint
*watchpoint
)
366 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
368 if (nds32_v3m
->next_hwp_index
<= 0) {
369 if (nds32_v3m
->nds32
.global_stop
)
375 /* update next place to put hardware watchpoint */
376 nds32_v3m
->next_hwp_index
--;
377 nds32_v3m
->used_n_wp
--;
382 struct nds32_v3_common_callback nds32_v3m_common_callback
= {
383 .check_interrupt_stack
= nds32_v3m_check_interrupt_stack
,
384 .restore_interrupt_stack
= nds32_v3m_restore_interrupt_stack
,
385 .activate_hardware_breakpoint
= nds32_v3m_activate_hardware_breakpoint
,
386 .activate_hardware_watchpoint
= nds32_v3m_activate_hardware_watchpoint
,
387 .deactivate_hardware_breakpoint
= nds32_v3m_deactivate_hardware_breakpoint
,
388 .deactivate_hardware_watchpoint
= nds32_v3m_deactivate_hardware_watchpoint
,
391 static int nds32_v3m_target_create(struct target
*target
, Jim_Interp
*interp
)
393 struct nds32_v3m_common
*nds32_v3m
;
395 nds32_v3m
= calloc(1, sizeof(*nds32_v3m
));
399 nds32_v3_common_register_callback(&nds32_v3m_common_callback
);
400 nds32_v3_target_create_common(target
, &(nds32_v3m
->nds32
));
405 /* talk to the target and set things up */
406 static int nds32_v3m_examine(struct target
*target
)
408 struct nds32_v3m_common
*nds32_v3m
= target_to_nds32_v3m(target
);
409 struct nds32
*nds32
= &(nds32_v3m
->nds32
);
410 struct aice_port_s
*aice
= target_to_aice(target
);
412 if (!target_was_examined(target
)) {
413 CHECK_RETVAL(nds32_edm_config(nds32
));
415 if (nds32
->reset_halt_as_examine
)
416 CHECK_RETVAL(nds32_reset_halt(nds32
));
420 aice_read_debug_reg(aice
, NDS_EDM_SR_EDM_CFG
, &edm_cfg
);
422 /* get the number of hardware breakpoints */
423 nds32_v3m
->n_hbr
= (edm_cfg
& 0x7) + 1;
424 nds32_v3m
->used_n_wp
= 0;
426 /* get the number of hardware watchpoints */
427 /* If the WP field is hardwired to zero, it means this is a
428 * simple breakpoint. Otherwise, if the WP field is writable
429 * then it means this is a regular watchpoints. */
430 nds32_v3m
->n_hwp
= 0;
431 for (int32_t i
= 0 ; i
< nds32_v3m
->n_hbr
; i
++) {
432 /** check the hardware breakpoint is simple or not */
434 aice_write_debug_reg(aice
, NDS_EDM_SR_BPC0
+ i
, 0x1);
435 aice_read_debug_reg(aice
, NDS_EDM_SR_BPC0
+ i
, &tmp_value
);
440 /* hardware breakpoint is inserted from high index to low index */
441 nds32_v3m
->next_hbr_index
= nds32_v3m
->n_hbr
- 1;
442 /* hardware watchpoint is inserted from low index to high index */
443 nds32_v3m
->next_hwp_index
= 0;
445 LOG_INFO("%s: total hardware breakpoint %" PRId32
" (simple breakpoint %" PRId32
")",
446 target_name(target
), nds32_v3m
->n_hbr
, nds32_v3m
->n_hbr
- nds32_v3m
->n_hwp
);
447 LOG_INFO("%s: total hardware watchpoint %" PRId32
, target_name(target
), nds32_v3m
->n_hwp
);
449 nds32
->target
->state
= TARGET_RUNNING
;
450 nds32
->target
->debug_reason
= DBG_REASON_NOTHALTED
;
452 target_set_examined(target
);
457 /** Holds methods for NDS32 V3m targets. */
458 struct target_type nds32_v3m_target
= {
462 .arch_state
= nds32_arch_state
,
464 .target_request_data
= nds32_v3_target_request_data
,
467 .resume
= nds32_resume
,
470 .assert_reset
= nds32_assert_reset
,
471 .deassert_reset
= nds32_v3m_deassert_reset
,
473 /* register access */
474 .get_gdb_reg_list
= nds32_get_gdb_reg_list
,
477 .read_buffer
= nds32_v3_read_buffer
,
478 .write_buffer
= nds32_v3_write_buffer
,
479 .read_memory
= nds32_v3_read_memory
,
480 .write_memory
= nds32_v3_write_memory
,
482 .checksum_memory
= nds32_v3_checksum_memory
,
484 /* breakpoint/watchpoint */
485 .add_breakpoint
= nds32_v3m_add_breakpoint
,
486 .remove_breakpoint
= nds32_v3m_remove_breakpoint
,
487 .add_watchpoint
= nds32_v3m_add_watchpoint
,
488 .remove_watchpoint
= nds32_v3m_remove_watchpoint
,
489 .hit_watchpoint
= nds32_v3_hit_watchpoint
,
493 .virt2phys
= nds32_virtual_to_physical
,
494 .read_phys_memory
= nds32_read_phys_memory
,
495 .write_phys_memory
= nds32_write_phys_memory
,
497 .run_algorithm
= nds32_v3_run_algorithm
,
499 .commands
= nds32_command_handlers
,
500 .target_create
= nds32_v3m_target_create
,
501 .init_target
= nds32_v3_init_target
,
502 .examine
= nds32_v3m_examine
,
504 .get_gdb_fileio_info
= nds32_get_gdb_fileio_info
,
505 .gdb_fileio_end
= nds32_gdb_fileio_end
,